Hello

29. JWT토큰 서버 구축 완료

by 볼빵빵오춘기

JwtAuthorizationFilter.java - 생성 및 코드 작성

  • config > jwt 밑에 JwtAuthorizationFilter.java 생성한다.
  • BasicAuthenticationFilter extends 해준다.
    • 시큐리티가 filter를 가지고 있는데 그 필터중에 BasicAuthenticationFilter 라는 것이 있다.
    • 권한이나 인증이 필요한 특정 주소를 요청했을 때 위 필터를 무조건 타게 되어있다.
    • 만약에 권한이 인증이 필요한 주소가 아니라면 이 필터를 안탄다.
public class JwtAuthorizationFilter extends BasicAuthenticationFilter {

		// constructor 가 없어 error가 나므로 constructor 생성
    public JwtAuthorizationFilter(AuthenticationManager authenticationManager, UserRepository userRepository) {
        super(authenticationManager);
        System.out.println("인증이나 권한이 필요한 주소가 요청이 됨.");
    }

}

 

SecurityConfig.java - configure()코드 추가

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .addFilter(corsFilter) // @CrossOrigin(인증x), 시큐리티 필터에 등록(인증o)
                .csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .formLogin().disable()
                .httpBasic().disable()
                .addFilter(new JwtAuthenticationFilter(authenticationManager())) // AuthenticationManager
                .addFilter(new JwtAuthorizationFilter(authenticationManager(),userRepository))
                .authorizeRequests()
                .antMatchers("/api/v1/user/**")
                .access("hasRole('ROLE_USER') or hasRole('ROLE_MANAGER') or hasRole('ROLE_ADMIN')")
                .antMatchers("/api/v1/manager/**")
                .access("hasRole('ROLE_MANAGER') or hasRole('ROLE_ADMIN')")
                .antMatchers("/api/v1/admin/**")
                .access("hasRole('ROLE_ADMIN')")
                .anyRequest().permitAll();
    }

 

JwtAuthorizationFilter.java - doFilterInternal() 코드 작성

코드 작성1

public class JwtAuthorizationFilter extends BasicAuthenticationFilter {

    public JwtAuthorizationFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }

    // 인증이나 권한이 필요한 주소요청이 있을 때 해당 필터를 타게 된다.
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        super.doFilterInternal(request,response,chain)
				System.out.println("인증이나 권한이 필요한 주소가 요청이 됨.");
    }
}

 

코드 작성2

public class JwtAuthorizationFilter extends BasicAuthenticationFilter {

    public JwtAuthorizationFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }

    // 인증이나 권한이 필요한 주소요청이 있을 때 해당 필터를 타게 된다.
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
//        super.doFilterInternal(request, response, chain);
        System.out.println("인증이나 권한이 필요한 주소가 요청이 됨.");
        String jwtHeader = request.getHeader("Authorization");
        System.out.println("jwtHeader : "+jwtHeader);
    }
}

 

코드작성3

public class JwtAuthorizationFilter extends BasicAuthenticationFilter {

    private  UserRepository userRepository;

    public JwtAuthorizationFilter(AuthenticationManager authenticationManager, UserRepository userRepository) {
        super(authenticationManager);
        this.userRepository = userRepository;
    }

    // 인증이나 권한이 필요한 주소요청이 있을 때 해당 필터를 타게 된다.
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
//        super.doFilterInternal(request, response, chain);
        System.out.println("인증이나 권한이 필요한 주소가 요청이 됨.");
        String jwtHeader = request.getHeader("Authorization");
        System.out.println("jwtHeader : "+jwtHeader);

        // header가 있는지 확인
        if(jwtHeader == null|| !jwtHeader.startsWith("Bearer")){
            chain.doFilter(request,response); 
            return; // 
        }

        // JWT 토큰을 검증을 해서 정상적인 사용자인지 확인
        String jwtToken = request.getHeader("Authorization").replace("Bearer ","");
        String username = JWT.require(Algorithm.HMAC512("cos")).build().verify(jwtToken)
                .getClaim("username").asString();

        // 서명이 정상적으로 됐다면
        if(username!=null){

        }

    }
}

 

SecurityConfig.java - UserRepository 타입 변수 선언 및 configure() - addFilter()에 파라미터 추가

@Override
    protected void configure(HttpSecurity http) throws Exception {
//        http.addFilter(new MyFilter1()); // 에러
//        http.addFilterBefore(new MyFilter1(), BasicAuthenticationFilter.class); // 필터가 실행되는지 test
//        http.addFilterBefore(new MyFilter3(), BasicAuthenticationFilter.class); // 필터1,2를 만들로 FilterConfig에서 만든 후 Security 필터가 먼저 실행되는지 아니면 내가 만든 필터가 먼저 실행되는지 test

        http
                .addFilter(corsFilter) // @CrossOrigin(인증x), 시큐리티 필터에 등록(인증o)
                .csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .formLogin().disable()
                .httpBasic().disable()
                .addFilter(new JwtAuthenticationFilter(authenticationManager())) // AuthenticationManager
                .addFilter(new JwtAuthorizationFilter(authenticationManager(),userRepository))
                .authorizeRequests()
                .antMatchers("/api/v1/user/**")
                .access("hasRole('ROLE_USER') or hasRole('ROLE_MANAGER') or hasRole('ROLE_ADMIN')")
                .antMatchers("/api/v1/manager/**")
                .access("hasRole('ROLE_MANAGER') or hasRole('ROLE_ADMIN')")
                .antMatchers("/api/v1/admin/**")
                .access("hasRole('ROLE_ADMIN')")
                .anyRequest().permitAll();
    }

}

 

JwtAuthorizationFilter.java - 생성자에 파라미터 추가

private  UserRepository userRepository;

public JwtAuthorizationFilter(AuthenticationManager authenticationManager, UserRepository userRepository) {
    super(authenticationManager);
    this.userRepository = userRepository;
}

 

JwtAuthorizationFilter.java - doFilterInternal() 에서 서명이 정상일 때 부분에 코드 추가

@Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
//        super.doFilterInternal(request, response, chain);
        System.out.println("인증이나 권한이 필요한 주소가 요청이 됨.");
        String jwtHeader = request.getHeader("Authorization");
        System.out.println("jwtHeader : "+jwtHeader);

        // header가 있는지 확인
        if(jwtHeader == null|| !jwtHeader.startsWith("Bearer")){
            chain.doFilter(request,response);
            return;
        }

        // JWT 토큰을 검증을 해서 정상적인 사용자인지 확인
        String jwtToken = request.getHeader("Authorization").replace("Bearer ","");
        String username = JWT.require(Algorithm.HMAC512("cos")).build().verify(jwtToken)
                .getClaim("username").asString();

        // 서명이 정상적으로 됐다면
        if(username!=null){
            System.out.println("username 정상");
            User userEntity = userRepository.findByUsername(username); // 정상적으로 select가 되면 정상적인 사용자

            PrincipalDetails principalDetails = new PrincipalDetails(userEntity);

            // JWT 토큰 서명을 통해서 서명이 정상이면 Authentication 객체를 만들어 준다.
            Authentication authentication = new UsernamePasswordAuthenticationToken(principalDetails,null,principalDetails.getAuthorities());

            // 강제로 시큐리티의 세션에 접근하여 Authentication 객체를 저장
            SecurityContextHolder.getContext().setAuthentication(authentication);

        }
        chain.doFilter(request,response);
    }

 

RestApiController.java - 테스트를 위한 요청 주소 추가

// user, manager, admin 권한만 접근 가능
@GetMapping("/api/v1/user")
public String user(Authentication authentication){
    PrincipalDetails principalDetails = (PrincipalDetails) authentication.getPrincipal();
    System.out.println("user() authentication : "+principalDetails.getUsername());
    return "user";
}

// ]manager, admin 권한만 접근 가능
@GetMapping("/api/v1/manager")
public String manager(){
    return "manager";
}

// admin 권한만 접근 가능
@GetMapping("/api/v1/admin")
public String admin(){
    return "admin";
}

 

추가적으로 JwtProperties.java 생성 및 코드 추가

public interface JwtProperties {
    String SECRET = "cos"; // 우리 서버만 알고 있는 비밀값
    int EXPIRATION_TIME = 864000000; // 10일 (1/1000초)
    String TOKEN_PREFIX = "Bearer ";
    String HEADER_STRING = "Authorization";
}

블로그의 정보

Hello 춘기's world

볼빵빵오춘기

활동하기