0. 프로젝트 소개(Spring Security) 및 Security에 대하여
1. User Entity 생성(Spring Security)
2. User 회원가입 (Spring Secureity)
3.Jwt의 사용 이유 (Spring Security)
4. Authorization(인증)
- 4-0 Authorization(인증) - 프로세스 설명
- 4-1 Authentication(인증) - UserDetails, UserDetailsService 및 JwtService 생성
- 4-2 Authentication(인증) - UsernamePasswordAuthenticationfilter 생성
- 4-3 Authentication(인증) - CorsFilter(선택사항)
- 4-4 Authentication(인증) - SecurityConfig
5. Authorization(인가)
- 5-1 Authorization(인가) - Jwt 인가 관련 에러 처리
- 5-2 Authorization(인가) - Jwt 인가 서비스 로직 추가
- 5-3 Authorization(인가) - AuthorizationFilter 생성
- 5-4 Authorization(인가) - SecurityConfig에 인가 관련 method 추가
6. OAuth
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());
}
로그인 실패 메시지를 세팅해준다.
'SpringBoot Security' 카테고리의 다른 글
4-4 Authentication(인증) - SecurityConfig (0) | 2023.07.09 |
---|---|
4-3 Authentication(인증) - CorsFilter(선택사항) (0) | 2023.07.09 |
4-1 Authentication(인증) - UserDetails, UserDetailsService 및 JwtService 생성 (0) | 2023.07.09 |
4-0 Authorization(인증) - 프로세스 설명 (0) | 2023.07.08 |
3. Jwt의 사용 이유 (Spring Security) (0) | 2023.06.28 |