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 |
Tags
- 반환
- Security
- Codewars
- response
- Spring
- 헬스체크
- 프로퍼티
- @Value
- Boot
- RequestParam
- ResponseDto
- Docker
- enum
- yml
- 플라이웨이트
- redis
- 로그인
- RequestBody
- JWT
- 디자인 패턴
- @RequestParam
- 코딩테스트
- DTO
- @RequestBody
- Request
- actuator
- springboot
- 파라미터
- property
- 코드워즈
Archives
- Today
- Total
있을 유, 참 진
[JWT] 로그인 구현 2::로그인 필터 구현, Spring Security에 적용하기 본문
JWT Filter 생성
- JwtSecurityConfig
Spring Security 공통 에러처리
- JwtAccessDeniedHandler
- JwtAuthenticationEntryPoint
WebSecurity에 값 설정
JWT Filter 생성
💡 JWT 토큰을 활용해 Security에서 인가를 처리하는 필터를 생성, 차후 `UsernamePasswordAuthenticationFilter` 전에 들어가 JWT의 정보를 통해 유저의 인가를 처리한다.
@Slf4j
@RequiredArgsConstructor
public class JwtFilter extends GenericFilter {
//헤더에서 받아올 이름 지정
public static final String AUTHORIZATION_HEADER = "Authorization";
private final JwtTokenProvider tokenProvider;
/**
* JWT 필터 추가
* @param request The request to process
* @param response The response associated with the request
* @param chain Provides access to the next filter in the chain for this
* filter to pass the request and response to for further
* processing
*
* @throws IOException
* @throws ServletException
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String jwtToken = resolveToken(httpServletRequest);
String requestURI = httpServletRequest.getRequestURI();
if(StringUtils.hasText(jwtToken) && tokenProvider.validateToken(jwtToken)) {
//토큰 값에서 Authentication 값으로 가공해서 반환 후 저장
Authentication authentication = tokenProvider.getAuthentication(jwtToken);
SecurityContextHolder.getContext().setAuthentication(authentication);
log.info("Security Context에 '{}' 인증 정보를 저장했습니다, uri: {}", authentication.getName(), requestURI);
} else {
log.info("유효한 JWT 토큰이 없습니다. requestURI : {}", requestURI);
}
//다음 필터로 넘기기
chain.doFilter(request, response);
}
/**
* HttpServletRequest에서 `Authorization` 헤더를 받음.
* 헤더에서 'Bearer'로 시작하는 토큰이 있으면 'Bearer' 부분 제거하고 토큰 값 반환 아니면 널 값 반환
* @param request
* @return
*/
private String resolveToken(HttpServletRequest request) {
String bearerToken = request.getHeader(AUTHORIZATION_HEADER);
if(StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) return bearerToken.substring(7);
return null;
}
}
JwtSecurityConfig
💡 앞서 만든 필터를 Security에 적용하기 위한 Config 생성, Security filter에 앞서 말한 `UsernamePasswordAuthenticationFilter` 앞에 만들어진 JWT필터를 적용해 준다.
@RequiredArgsConstructor
public class JwtSecurityConfig extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
private final JwtTokenProvider jwtTokenProvider;
@Override
public void configure(HttpSecurity httpSecurity) {
//UsernamePasswordAuthenticationFilter 뒤에 저장 생성자 주입 받은 JwtTokenProvider를 넣어준다.
httpSecurity.addFilterBefore(
new JwtFilter(jwtTokenProvider),
UsernamePasswordAuthenticationFilter.class
);
}
}
Spring Security 공통 에러처리
JwtAccessDeniedHandler
💡 권한이 없는 사용자(ROLE_ADMIN을 가지고 싶다던가..)가 보호된 자원에 액세스하려 할 때 처리 방법
public class JwtAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
response.sendError(HttpServletResponse.SC_FORBIDDEN);
}
}
JwtAuthenticationEntryPoint
💡 인증되지 않은 사용자(로그인 되지 않은)가 보호된 리소스에 접근하려고 시도하면 실행되는 예외 처리
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
}
WebSecurity에 값 설정
@EnableGlobalMethodSecurity(prePostEnabled = true)
@RequiredArgsConstructor
@EnableWebSecurity
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private final JwtTokenProvider jwtTokenProvider;
private final JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
private final JwtAccessDeniedHandler jwtAccessDeniedHandler;
// 회원가입 시 비밀번호 암호화를 위한 PasswordEncoder 빈 등록
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
public void configure(WebSecurity web) {
web
.ignoring()
.antMatchers("/h2-console/**", "/favicon.ico");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
//jwt는 필요가 없으므로 csrf 비활성화
.csrf().disable()
//세션 사용하지 않음
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
//Exception 처리를 위한 부분
.exceptionHandling()
.authenticationEntryPoint(jwtAuthenticationEntryPoint)
.accessDeniedHandler(jwtAccessDeniedHandler)
.and()
.authorizeRequests() //ServletRequest를 사용하는 요청에 대한 접근 제한 설정
.antMatchers(HttpMethod.POST, "/api/auth/**").permitAll() //검증 없이 이용가능(Post 요청 가능)
.anyRequest().authenticated()
.and()
//JwtSecurityConfig 적용
.apply(new JwtSecurityConfig(jwtTokenProvider));
}
}
'Spring > JWT' 카테고리의 다른 글
[JWT] 로그인 구현 1::로그인 기능 구현, JWT Provider 생성 (2) | 2023.04.11 |
---|---|
[JWT] JWT 회원가입 구현하기 (0) | 2023.04.07 |
[JWT] Json Web Token 인증 (2) | 2023.04.05 |
Comments