본문 바로가기
Back-End/Security

Spring Security + JWT (1)

by 어렵다어려웡 2022. 4. 15.

토큰 기반 인증 시스템의 대표적인 예시로 JWT(Json Web Token) 을 포스팅해보려고 합니다.

구현 코드관련 포스팅은 추후에 쓰겠습니다.

 

Spring Security를 기반으로 JWT를 구현하기 위해서는 Security의 동작방식을 이해하고

추상클래스나 인터페이스를 구현할 줄 알아야 합니다.

 

간단하게 예시..

	@Override
	public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
			throws AuthenticationException {
		if (this.postOnly && !request.getMethod().equals("POST")) {
			throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
		}
		String username = obtainUsername(request);
		username = (username != null) ? username : "";
		username = username.trim();
		String password = obtainPassword(request);
		password = (password != null) ? password : "";
		UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
		// Allow subclasses to set the "details" property
		setDetails(request, authRequest);
		return this.getAuthenticationManager().authenticate(authRequest);
	}
    
    @Nullable
	protected String obtainUsername(HttpServletRequest request) {
		return request.getParameter(this.usernameParameter);
	}

기존의 Spring Security는 세션&쿠키 기반으로 이루어집니다.

위의 attemptAuthentication 메서드는 UsernamePasswordAuthenticationFilter 클래스의 메서드로

로그인 요청을 했을 때 여러 필터 중 처음 접근되는 메서드입니다.

 

Spring Security 기본적으로 JSP의 <Form> 태그를 전송해서 로그인을 요청합니다.

그렇기 떄문에 obtainUsername 의 반환값이 request.getParameter(..) 로 코드가 작성되어 있다.

 

하지만, JWT를 사용하게 된다면 코드가 달라져야 합니다.

 

JWT는 기본적으로 요청시 Headers 를 전달하며 JSON 형식의 데이터를 받습니다.

그러므로 request.getParameter(..) 를 통해서 받을 수 없고 request.getInputStream()을 통해서 값을 추출해야 합니다.

 

 @Override
    public Authentication attemptAuthentication(HttpServletRequest request,
                                                HttpServletResponse response) throws AuthenticationException {

        try {
            AttemptLoginDto attemptLoginDto = new ObjectMapper().readValue(request.getInputStream(), AttemptLoginDto.class);

            return getAuthenticationManager().authenticate(
                    new UsernamePasswordAuthenticationToken(
                            attemptLoginDto.getEmail(),
                            attemptLoginDto.getPassword()
                    )
            );
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

 

그래서 인증 필터를 개발자가 구현해야 하는 상황이 발생합니다.

 

그리고 토큰기반을 이용하기 떄문에 세션에 대한 설정을 변경해주고 이후에 JWT 토큰 관련 객체를 생성하고

토큰에 대한 유효성 검사를 구현하면 됩니다.