JWT

조현재·2023년 2월 1일
0

MSA

목록 보기
13/17

AuthenticationFilter 에 로그인 성공했을 때 로직에서 UserDto를 반환받기

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
                                            Authentication authResult) throws IOException, ServletException {
        log.debug(((User)authResult.getPrincipal()).getUsername());
        
        String userName = ((User)authResult.getPrincipal()).getUsername();
        UserDto userDetails = userService.getUserDetailsByEmail(userName);

    }

기존의 log만 찍었던 로직을 다음과 같이 입력 받은 userName 값으로 userId값을 받아올 수 있도록 변경한다.

여기서 userService에서 getUserDetailsByEmail(userName)이 정의 되지 않았기 때문에 정의해줘야한다
생성자에 UserService와 Enviroment값을 매개변수로 설정했기 때문에
WebSecurity에서 생성자로 Filter를 생성하는 부분에도 값을 넣어줘야한다.

    private AuthenticationFilter getAuthenticationFilter(AuthenticationManager authenticationManager) {
        return new AuthenticationFilter(authenticationManager, userService, env);
    }

UserServiceImpl에서

    @Override
    public UserDto getUserDetailsByEmail(String email) {

        UserEntity userEntity = userRepository.findByEmail(email);

        if(userEntity == null)
            throw new UsernameNotFoundException(email);

        return new ModelMapper().map(userEntity, UserDto.class);
    }


Jwt 추가

        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>

application.yml

token:
  expiration_time: 86400000 #ms단위 하루설정
  secret: user_token

toeken을 이용해준다

//로그인 성공했을 때 로직
    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
                                            Authentication authResult) throws IOException, ServletException {
        log.debug(((User)authResult.getPrincipal()).getUsername());
        String userName = ((User)authResult.getPrincipal()).getUsername();
        UserDto userDetails = userService.getUserDetailsByEmail(userName);

        String token = Jwts.builder()
                .setSubject(userDetails.getUserId()) //token 내용
                .setExpiration(new Date(System.currentTimeMillis() +
                        Long.parseLong(env.getProperty("token.expiration_time")))) //파기 날짜
                .signWith(SignatureAlgorithm.HS512, env.getProperty("token.secret")) //token 생성 알고리즘과 키 값
                .compact();

        response.addHeader("token", token);
        response.addHeader("userId", userDetails.getUserId()); //원래는 반환하지 않는 데이터이지만 확인용

    }

또한
userservice에서 jwt를 통해 토큰을 발급 받는 기능을 추가했으니 gateway에도
jwt dependency추가해준다.

@Component
@Slf4j
public class AuthorizationHeaderFilter extends AbstractGatewayFilterFactory<AuthorizationHeaderFilter.Config> {

    private Environment env;

    //생성시 Config class를 상속받은 Factory로 넘겨줘야해서 lombok을 사용하지 않고 다음과 같이 처리
    public AuthorizationHeaderFilter(Environment env) {
        super(Config.class);
        this.env = env;
    }

    public static  class Config{}

    //login -> token -> users (with token) -> header(include token)
    @Override
    public GatewayFilter apply(Config config) {
        return ((exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();

            //header에 HttpHeaders.AUTHORIZATION 값이 존재하는지 확인
            if(!request.getHeaders().containsKey(HttpHeaders.AUTHORIZATION)){
                return onError(exchange, "no authorization header", HttpStatus.UNAUTHORIZED);
            }

            String authorizationHeader = request.getHeaders().get(HttpHeaders.AUTHORIZATION).get(0);//배열이라서
            String jwt = authorizationHeader.replace("Bearer", "");

            if(!isJwtValid(jwt)){
                return onError(exchange, "JWT Token is not valid", HttpStatus.UNAUTHORIZED);
            }

            return chain.filter(exchange);
        });

    }
	
    //token이 유효한지 확인
    private boolean isJwtValid(String jwt) {
        boolean returnValue = true;

        String subject = null;

        try {
            subject = Jwts.parser().setSigningKey(env.getProperty("token.secret"))
                    .parseClaimsJws(jwt).getBody()
                    .getSubject();
			//token의 내용을 가져옴
            //jws로 파싱하고 그 앞에서 subject값
        } catch (Exception ex){
            returnValue = false;
        }

        if(subject == null || subject.equals("")){
            returnValue = false;
        }

        return returnValue;
    }

	//에러 발생시 에러 값을 response
    //Mono, Flux -> Spring WebFlux / 데이터 단위 단일=Mono, 복수=Flux
    private Mono<Void> onError(ServerWebExchange exchange,
                               String err,
                               HttpStatus httpStatus) {

        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(httpStatus);

        log.error(err);
        return response.setComplete();

    }


}

그리고 yml에 AuthorizationHeaderFilter 설정해준다

        - id: user-service
          uri: lb://USER-SERVICE
          predicates:
            - Path=/user-service/login
            - Method=POST
          filters:
            - RemoveRequestHeader=Cookie
            - RewritePath=/user-service/(?<segment>.*), /$\{segment}
        - id: user-service
          uri: lb://USER-SERVICE
          predicates:
            - Path=/user-service/users
            - Method=POST
          filters:
            - RemoveRequestHeader=Cookie
            - RewritePath=/user-service/(?<segment>.*), /$\{segment}
        - id: user-service
          uri: lb://USER-SERVICE
          predicates:
            - Path=/user-service/**
            - Method=GET
          filters:
            - RemoveRequestHeader=Cookie
            - RewritePath=/user-service/(?<segment>.*), /$\{segment}
            - AuthorizationHeaderFilter

user-service중 GET방식에 AuthorizationHeaderFilter filter를 추가

Authenticate 필요X post-> /user-service/users (회원가입)
post-> /user-service/login (로그인)
Authenticate 필요O GET-> /user-service/users (회원정보)

Bearer Token에 발급 받은 토큰을 입력 후 진행 과정을 디버그로 확인해보자

AuthorizationHeaderFilter의 apply()로 요청이 들어가고

//header에 HttpHeaders.AUTHORIZATION 값이 존재하는지 확인
            if(!request.getHeaders().containsKey(HttpHeaders.AUTHORIZATION)){
                return onError(exchange, "no authorization header", HttpStatus.UNAUTHORIZED);
            }

이걸로 인해 Header에 Authorization : value 가 존재하는지 확인

value에 Bearer + token으로 값이 넘어오는데 해당 값을 replace()로 처리해주고 isJwtValid()를 통해 유효성을 체크

profile
내일이 다른

0개의 댓글