BE전문가 프로젝트

4-2 Authentication(인증) - UsernamePasswordAuthenticationfilter 생성 본문

SpringBoot Security

4-2 Authentication(인증) - UsernamePasswordAuthenticationfilter 생성

원호보고서 2023. 7. 9. 20:22

JwtAuthenticationFilter 

/**
 * @package com.example.spring_security.config.security.jwt.filter
 * @class   JwtAuthenticationFilter
 * @brief   인증 필터
 * @author  최원호
 * @date    2023.06.22
 * version  1.0
 */
@Slf4j
@RequiredArgsConstructor
public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    private final JwtService jwtService;
    private final AuthenticationManager authenticationManager;

    /**
     * @brief   인증 요청시에 실행되는 함수 (/login 요청 시 실행됨)
     * @param   req
     * @param   res
     * @return  Authentication               회원가입 결과
     */
    public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res) throws AuthenticationException {

        ObjectMapper om = new ObjectMapper();
        Authentication authentication = null;

        try {
            LoginRequestDto loginDto = om.readValue(req.getInputStream(), LoginRequestDto.class);

            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginDto.getEmail(), loginDto.getPassword());

            log.info("********************************************************");
            log.info("*             success to create token                  *");
            log.info("********************************************************");

            authentication = authenticationManager.authenticate(authenticationToken);

        } catch (IOException e) {
            e.printStackTrace();
        }

        /* 4. authentication 반환 */
        return authentication;
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
                                            Authentication authResult) throws IOException, ServletException {
        log.info("**************************************************************");
        log.info("*                  success to authentication                 *");
        log.info("**************************************************************");

        PrincipalDetails principalDetails = (PrincipalDetails) authResult.getPrincipal();

        String accessToken = jwtService.createAccessToken(principalDetails.getUsername());
        String refreshToken = jwtService.createRefreshToken();

        LoginResponseDto user = jwtService.retrieveByEmail(principalDetails.getUsername());
        jwtService.setRefreshToken(user.getUserId(), refreshToken);

        jwtService.setAccessTokenToHeader(response, accessToken);
        jwtService.setRefreshTokenToHeader(response, refreshToken);
        jwtService.setResponseMessage(true, response, "로그인 성공");
    }

    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
        log.info("**************************************************************");
        log.info("*                  fail to authentication                    *");
        log.info("**************************************************************");

        jwtService.setResponseMessage(false, response, failed.getMessage());
    }
}

 

UsernamePasswordAuthenticationFilter

유저의 이름과 패스워드를 비교하여 인증을 거치는 필터라고 볼 수 있다.

POST로 요청이 왔는지 먼저 확인 후 request에서 username과 password를 추출하여UsernamePasswordAuthenticationToken을 생성한다.

 

 

토큰 생성

public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res) throws AuthenticationException {

    ObjectMapper om = new ObjectMapper();
    Authentication authentication = null;

    try {
        LoginRequestDto loginDto = om.readValue(req.getInputStream(), LoginRequestDto.class);

        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginDto.getEmail(), loginDto.getPassword());

        log.info("********************************************************");
        log.info("*             success to create token                  *");
        log.info("********************************************************");

        authentication = authenticationManager.authenticate(authenticationToken);

    } catch (IOException e) {
        e.printStackTrace();
    }

    /* 4. authentication 반환 */
    return authentication;
}

 

email, password 읽기

LoginRequestDto loginDto = om.readValue(req.getInputStream(), LoginRequestDto.class);

loginDto를 생성만든 후 json형태로 들어온 email과 password를 파싱해준다.

 

 

email과 password를 이용하여 token 발급

UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginDto.getEmail(), loginDto.getPassword());

 

 

Authentication객체 생성

authentication = authenticationManager.authenticate(authenticationToken);

authenticate(토큰) 함수가 호출 되면 인증 프로바이더가 UserDetailService의 loadUserByUsername(토큰의 첫번째 파라메터) 를 호출하고 UserDetails를 리턴받아서 토큰의 두번째 파라메터(credential)과 UserDetails(DB값)의 getPassword()함수로 비교해서 동일하면 Authentication 객체를 만들어서 필터체인으로 리턴해준다. 

 

 

필터 성공 method

@Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
                                            Authentication authResult) throws IOException, ServletException {
        log.info("**************************************************************");
        log.info("*                  success to authentication                 *");
        log.info("**************************************************************");

        PrincipalDetails principalDetails = (PrincipalDetails) authResult.getPrincipal();

        String accessToken = jwtService.createAccessToken(principalDetails.getUsername());
        String refreshToken = jwtService.createRefreshToken();

        LoginResponseDto user = jwtService.retrieveByEmail(principalDetails.getUsername());
        jwtService.setRefreshToken(user.getUserId(), refreshToken);

        jwtService.setAccessTokenToHeader(response, accessToken);
        jwtService.setRefreshTokenToHeader(response, refreshToken);
        jwtService.setResponseMessage(true, response, "로그인 성공");
    }

 

UserDetails객체 생성

PrincipalDetails principalDetails = (PrincipalDetails) authResult.getPrincipal();

 

AccessToken 및 RefreshToken 생성 후 헤더에 추가

String accessToken = jwtService.createAccessToken(principalDetails.getUsername());
String refreshToken = jwtService.createRefreshToken();

LoginResponseDto user = jwtService.retrieveByEmail(principalDetails.getUsername());
jwtService.setRefreshToken(user.getUserId(), refreshToken);

jwtService.setAccessTokenToHeader(response, accessToken);
jwtService.setRefreshTokenToHeader(response, refreshToken);
jwtService.setResponseMessage(true, response, "로그인 성공");

access토큰과 refresh토큰을 jwtService에 정의한 메소드를 이용하여 생성 후 

해당 Entity를 email을 통하여 조회 후 토큰을 update해준다.

Header에 토큰을 세팅한 후 로그인 성공 메시지를 세팅해준다.

 

 

필터 실패 method

@Override
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
    log.info("**************************************************************");
    log.info("*                  fail to authentication                    *");
    log.info("**************************************************************");

    jwtService.setResponseMessage(false, response, failed.getMessage());
}

로그인 실패 메시지를 세팅해준다.

 

Comments