jwt가 적용된 SpringBoot security에서 CORS 처리
jwt가 적용된 SpringBoot security에서 CORS 처리
- 회사내부 프로젝트에서 cors 관련 이슈로 고생하는 동료와 함께 들여다 봄.
- 교훈
- 시큐리티 설정은 순서가 중요하다. Is the order matter? Yes!!!
- 안된다고 이렇게 저렇게 코드를 휘젓지 말자. 나의 경우, 처음에 콘트롤러에서
@CrossOrigin
가지고 이렇게 저렇게 하다가 누락되어 되지 않았던 경우였다. 당연히 되있겠거니 한것이다. 누가 바꿨냐면 바로 나. 그러나 기억못함.SecurityConfig.java
```java
import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.WebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.cors.CorsUtils; import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import javax.servlet.Filter;
@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Value(“${jwt.secret}”) private String secret;
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers("/css/**", ....., "/img/**", "/js/**")
;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
Filter filter = new JwtAuthenticationFilter(authenticationManager(), jwtUtil());
http
.csrf().disable()
.addFilter(filter)
.authorizeRequests()
.requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
.antMatchers("/login").permitAll()
.antMatchers("/init").hasRole(Role.NOT_ACTIVATE.name())
.antMatchers("/admin/**").hasRole(Role.ADMIN.name())
.
.
.
.
.
.anyRequest().hasAnyRole(Role.USER.name(), Role.ADMIN.name())
.and().cors().configurationSource(getConfig())
.and().headers().frameOptions().sameOrigin()
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
;
}
private CorsConfigurationSource getConfig() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.addAllowedOrigin("*");
configuration.addAllowedMethod("*");
configuration.addAllowedHeader("*");
configuration.setAllowCredentials(true);
configuration.setMaxAge(5000L);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public JwtUtil jwtUtil() {
return new JwtUtil(secret);
} }
### SampleController.java
```java
@Slf4j
@RestController
@RequestMapping("/sample")
@CrossOrigin
public class SampleController {
private final AdminService adminService;
public AdminController(final AdminService adminService) {
this.adminService = adminService;
}
/**
* 총 사원 수 조회
*
* @return
*/
@GetMapping("/test")
public String test() {
return "Yes";
}
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@Slf4j
public class JwtAuthenticationFilter extends BasicAuthenticationFilter {
private JwtUtil jwtUtil;
public JwtAuthenticationFilter(AuthenticationManager authenticationManager, JwtUtil jwtUtil) {
super(authenticationManager);
this.jwtUtil = jwtUtil;
}
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain)
throws IOException, ServletException {
Authentication authentication = getAuthentication(request);
if (authentication != null) {
SecurityContext context = SecurityContextHolder.getContext();
context.setAuthentication(authentication);
}
chain.doFilter(request, response);
}
private Authentication getAuthentication(HttpServletRequest request) {
String token = request.getHeader(JwtConstants.AUTHORIZATION);
if (token == null) {
return null;
}
Claims claims = jwtUtil.getClaims(token.substring("Bearer ".length()));
List<GrantedAuthority> grantedAuthorityList = new ArrayList<>();
if (claims.containsKey(JwtConstants.ROLE)) {
GrantedAuthority grantedAuthority
= new SimpleGrantedAuthority("ROLE_" + claims.get(JwtConstants.ROLE));
grantedAuthorityList.add(grantedAuthority);
}
Authentication authentication =
new UsernamePasswordAuthenticationToken(claims, null, grantedAuthorityList);
logger.debug(authentication.toString());
return authentication;
}
}
jwt와 cors
Comments