Notice
Recent Posts
Recent Comments
Link
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 | 31 |
Tags
- java map 출력
- 노베이스부트캠프
- java참조자료형
- javaJRE
- 코딩부트캠프후기
- java최솟값구하기
- java map
- java set 출력
- java set 저장
- 작은수제거하기
- 비전공자sqld
- java 자료구조 활용
- 항해99후기
- 프로그래머스제일작은수
- sqld자격증합격
- 프로그래머스
- 인터프린터언어
- javaJVM
- 격파르타합격후기
- 항해15기
- 격파르타후기
- 컴파일
- java기본자료형
- 격파르타비전공자
- 격파르타장점
- java list 저장
- java알고리즘문제풀이
- java알고리즘
- java map 저장
- java list 출력
Archives
- Today
- Total
코딩과 결혼합니다
231013 - [Game_Crew] 로그인 구현 본문
728x90
사용자의 세부정보를 제공하는 클래스
public record UserDetailsImpl(User user) implements UserDetails {
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.getEmail();
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return Collections.emptyList();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
📌레코드 타입
java 14부터 도입된 데이터 저장용 타입으로, 불변성과 패턴 매칭 기능을 제공한다.
UserDetailsImpl 클래스의 필드와 관련된 게터와 생성자 등을 제거할 수 있어 코드가 좀 더 간결해진다.
사용자의 세부 정보를 데이터베이스에서 가져와 UserDetailsImpl 객체로 변환하여 반환
@Service
@Setter
public class UserDetailsServiceImpl implements UserDetailsService {
private final UserRepository userRepository;
public UserDetailsServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
User user = userRepository.findByEmail(email)
.orElseThrow(() -> new UsernameNotFoundException("Not Found " + email));
return new UserDetailsImpl(user);
}
}
사용자의 로그인 요청을 처리하고 JWT 토큰을 생성하여 응답 바디에 담아 전송
@Slf4j(topic = "로그인 및 JWT 생성")
public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private final JwtUtil jwtUtil;
public JwtAuthenticationFilter(JwtUtil jwtUtil) {
this.jwtUtil = jwtUtil;
setFilterProcessesUrl("/auth/login");
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
try {
LoginRequestDto requestDto = new ObjectMapper().readValue(request.getInputStream(), LoginRequestDto.class);
return getAuthenticationManager().authenticate(
new UsernamePasswordAuthenticationToken(
requestDto.getEmail(),
requestDto.getPassword(),
null
)
);
} catch (IOException e) {
log.error(e.getMessage());
throw new RuntimeException(e.getMessage());
}
}
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) {
String username = ((UserDetailsImpl) authResult.getPrincipal()).getUsername();
String token = jwtUtil.createToken(username);
// JWT 토큰을 응답 바디에 담아 전송
try {
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.getWriter().write("{\"token\": \"" + token + "\"}");
response.getWriter().flush();
response.getWriter().close();
} catch (IOException e) {
log.error("Failed to write token to response body: {}", e.getMessage());
throw new RuntimeException("Failed to write token to response body");
}
}
@Override
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) {
response.setStatus(401);
}
}
- setFilterProcessesUrl() 메서드를 호출하여 로그인 요청 URL을 "/auth/login"로 설정
- attemptAuthentication(): 사용자의 로그인 요청을 처리. 전달받은 HttpServletRequest에서 입력 스트림으로부터 LoginRequestDto 객체를 읽어 오고 그 후, AuthenticationManager로 UsernamePasswordAuthenticationToken 객체를 생성하고 인증을 시도
- successfulAuthentication(): 인증에 성공한 경우 호출. Authentication 객체에서 인증된 사용자의 이메일(username) 정보를 가져와 JwtUtil.createToken() 메서드를 사용하여 JWT 토큰을 생성. 그리고 응답 바디에 JWT 토큰 값을 JSON 형식으로 담아 전송
- unsuccessfulAuthentication(): 인증에 실패한 경우 호출. 응답 상태 코드(401 Unauthorized)를 설정하여 클라이언트에게 실패했음을 알림
클래스 요청마다 실행되며, 전달된 JWT 토큰을 검증하고 인가된 사용자의 보안 컨텍스트에 인증 정보를 설정
@Slf4j(topic = "JWT 검증 및 인가")
public class JwtAuthorizationFilter extends OncePerRequestFilter {
private final JwtUtil jwtUtil;
private final UserDetailsServiceImpl userDetailsService;
public JwtAuthorizationFilter(JwtUtil jwtUtil, UserDetailsServiceImpl userDetailsService) {
this.jwtUtil = jwtUtil;
this.userDetailsService = userDetailsService;
}
@Override
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain filterChain) throws ServletException, IOException {
String tokenValue = jwtUtil.getJwtFromHeader(req);
if (StringUtils.hasText(tokenValue)) {
if (!jwtUtil.validateToken(tokenValue)) {
log.error("Token Error");
return;
}
Claims info = jwtUtil.getUserInfoFromToken(tokenValue);
try {
setAuthentication(info.getSubject());
} catch (Exception e) {
log.error(e.getMessage());
return;
}
}
filterChain.doFilter(req, res);
}
// 인증 처리
public void setAuthentication(String username) {
SecurityContext context = SecurityContextHolder.createEmptyContext();
Authentication authentication = createAuthentication(username);
context.setAuthentication(authentication);
SecurityContextHolder.setContext(context);
}
// 인증 객체 생성
private Authentication createAuthentication(String username) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
}
}
- doFilterInternal(): 요청마다 호출되어 JWT 토큰을 검증하고 인증 처리를 수행한다. 먼저, HttpServletRequest에서 JWT 토큰 값을 가져오고 그 후, jwtUtil.validateToken() 메서드를 사용하여 토큰의 유효성을 검사. 유효하지 않으면 로그에 오류 메시지를 기록하고 종료
- getUserInfoFromToken(): jwtUtil.getUserInfoFromToken() 메서드를 호출하여 JWT 토큰에서 클레임(Claims) 정보(예: 사용자 이름)를 추출
- setAuthentication(): SecurityContextHolder에서 보안 컨텍스트(SecurityContext)와 인증(Authentication) 객체를 생성하여 설정
- createAuthentication(): userDetailsService.loadUserByUsername(username)을 호출하여 주어진 username으로부터 UserDetails 객체(인증에 필요한 세부 정보)를 가져온다. 그리고 UsernamePasswordAuthenticationToken 객체로 인증(Authentication) 객체를 생성하여 반환
'코딩과 매일매일♥ > Game_Crew' 카테고리의 다른 글
| 231024 - [Game_Crew]JWT (0) | 2023.10.24 |
|---|---|
| 231021 - [Game_Crew]트러블 슈팅 : 지옥의 304 (1) | 2023.10.21 |
| 231018 - [Game_Crew]트러블슈팅 : 이메일 인증 구현하기 (0) | 2023.10.18 |
| 231012 - [Game_Crew]트러블 슈팅 : 회원가입 구현 (0) | 2023.10.12 |
| 231009 - [Game_Crew] 프로젝트 MVP (0) | 2023.10.09 |