SpringBoot OAuth + JWT
https://ozofweird.tistory.com/entry/Spring-Boot-Spring-Boot-JWT-OAuth2-2
[Spring Boot] Spring Boot, JWT, OAuth2 (2)
1. 환경 구축 - docker-compose.yml version: "3.7" services: db: image: mysql:latest restart: always command: --lower_case_table_names=1 container_name: local_mysql ports: - "13306:3306" environment:..
ozofweird.tistory.com
위 글을 따라서 로그인 예제를 진행했다.
<TokenAuthenticationFilter 코드>
import lombok.extern.slf4j.Slf4j;
import com.sungshin.croffle.config.auth.service.CustomUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Slf4j
public class TokenAuthenticationFilter extends OncePerRequestFilter {
@Autowired
private TokenProvider tokenProvider;
@Autowired
private CustomUserDetailsService customUserDetailsService;
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
System.out.println("TokenAuthenticationFilter doFilterInternal");
try {
// header 에 bearer token 가져옴
String jwt = getJwtFromRequest(request);
// token 유효성 검사
if (StringUtils.hasText(jwt) && tokenProvider.validateToken(jwt)) {
Long userId = tokenProvider.getUserIdFromToken(jwt);
// repo에서 user를 찾아 인터페이스타입에 담아 spring security context 에 전달할 객체 가져옴
UserDetails userDetails = customUserDetailsService.loadUserById(userId);
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
} catch (Exception e) {
log.error("Security Context에서 사용자 인증을 설정할 수 없습니다.", e);
}
filterChain.doFilter(request, response);
}
private String getJwtFromRequest(HttpServletRequest request) {
System.out.println("TokenAuthenticationFilter getJwtFromRequest");
String bearerToken = request.getHeader("Authorization");
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
return bearerToken.substring(7);
}
return null;
}
}
접근 권한을 체크해야 하는 요청이 들어오면 doFilterInternal 함수로 들어오는데,
private String getJwtFromRequest(HttpServletRequest request) {
System.out.println("TokenAuthenticationFilter getJwtFromRequest");
String bearerToken = request.getHeader("Authorization");
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
return bearerToken.substring(7);
}
return null;
}
Header 에 담긴 Bearer 토큰을 체크해서 진행한다.
따라서 권한이 필요한 요청을 보내면, 로그인 후 redirect 됐던 url 에 쿼리스트링으로 보내진 token 값을 헤더에 Bearer 토큰으로 추가해야 한다.
> Bearer 토큰
- 토큰 포맷의 일종
- 인증 서버에서 생성된 암호화 토큰
TokenAuthenticationFilter 클래스에서 SpringSecurity Context 에 setAuthentication을 설정하는 부분이 있다.
UserDetails userDetails = customUserDetailsService.loadUserById(userId);
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
- userDetails : UserPrincipal 객체의 부모
-> customUserDetailsService.loadUserById(userId);
이 함수가 UserDetails(UserPrincipal) 객체를 리턴 - new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
- 첫번째 파라미터인 userDetails => Principal
- credentials: null
- authorities => userDetails 에 있는 authorities
이후 컨트롤러에서 Authentication 정보를 받을 수 있는데,
@GetMapping("/test")
public Response test(Authentication authentication) {
UserPrincipal userPrincipal = (UserPrincipal) authentication.getPrincipal();
return Response;
}
위와 같이 AuthenticationToken 에서 저장했던 user principal 정보를 가져온다.
[Spring Security] 현재 로그인한 사용자 정보 가져오기
Spring Security 에서 현재 인증된(로그인한) 사용자의 정보를 가져오는 방법 에 대해 살펴볼 것 입니다. 스프링의 다양한 메카니즘을 통해 현재 로그인 중인 사용자의 정보를 가져올 수 있는데, 대
itstory.tk
현재 로그인한 사용자 정보 가져오는 방법