[SPRING] oauth / token 요청에 대해 OPTIONS HTTP 메소드 허용
SPRINGoauth / token 요청에 대해 OPTIONS HTTP 메소드 허용
내 각도 응용 프로그램에 대한 oauth2 토큰 가져 오기를 사용하려고합니다. 구성이 잘 작동합니다 (모든 요청에 대해 인증이 올바르게 작동하며 토큰 가져 오기가 정상적으로 작동 함)하지만 한 가지 문제가 있습니다.
CORS 요청은 GET 전에 OPTIONS 요청이 서버로 전송되도록 요구합니다. 이를 악화시키기 위해 요청에는 인증 헤더가 포함되어 있지 않습니다. 나는이 요청을 항상 서버에서 수행 된 인증없이 200 상태로 반환하고 싶습니다. 가능한가? 어쩌면 내가 뭔가를 놓친거야.
내 봄 보안 설정 :
@Configuration
@EnableWebSecurity
@EnableAuthorizationServer
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private static final Logger log = LoggerFactory.getLogger(SecurityConfig.class);
@Inject
private UserService userService;
@Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
@Bean
public DefaultTokenServices tokenServices() {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
return defaultTokenServices;
}
@Bean
public WebResponseExceptionTranslator webResponseExceptionTranslator() {
return new DefaultWebResponseExceptionTranslator() {
@Override
public ResponseEntity<OAuth2Exception> translate(Exception e) throws Exception {
ResponseEntity<OAuth2Exception> responseEntity = super.translate(e);
OAuth2Exception body = responseEntity.getBody();
HttpHeaders headers = new HttpHeaders();
headers.setAll(responseEntity.getHeaders().toSingleValueMap());
headers.set("Access-Control-Allow-Origin", "*");
headers.set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");
headers.set("Access-Control-Max-Age", "3600");
headers.set("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
return new ResponseEntity<>(body, headers, responseEntity.getStatusCode());
}
};
}
@Bean
public AuthorizationServerConfigurer authorizationServerConfigurer() {
return new AuthorizationServerConfigurer() {
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
OAuth2AuthenticationEntryPoint oAuth2AuthenticationEntryPoint = new OAuth2AuthenticationEntryPoint();
oAuth2AuthenticationEntryPoint.setExceptionTranslator(webResponseExceptionTranslator());
security.authenticationEntryPoint(oAuth2AuthenticationEntryPoint);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("secret-client")
.secret("secret")
.authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit")
.authorities("ROLE_LOGIN")
.scopes("read", "write", "trust")
.accessTokenValiditySeconds(60 * 60 * 12); // 12 hours
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenServices(tokenServices());
endpoints.authenticationManager(authenticationManager());
}
};
}
@Override
protected AuthenticationManager authenticationManager() throws Exception {
return new AuthenticationManager() {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
log.warn("FIX ME: REMOVE AFTER DEBUG!!!!!!!!!!!!");
log.debug("authenticate: " + authentication.getPrincipal() + ":" + authentication.getCredentials());
final Collection<GrantedAuthority> authorities = new ArrayList<>();
WomarUser user = userService.findUser(authentication.getPrincipal().toString(), authentication.getCredentials().toString());
for (UserRole userRole : user.getRoles()) {
authorities.add(new SimpleGrantedAuthority(userRole.getName()));
}
return new UsernamePasswordAuthenticationToken(user.getLogin(), user.getPassword(), authorities);
}
};
}
@Bean
public OAuth2AuthenticationManager auth2AuthenticationManager() {
OAuth2AuthenticationManager oAuth2AuthenticationManager = new OAuth2AuthenticationManager();
oAuth2AuthenticationManager.setTokenServices(tokenServices());
return oAuth2AuthenticationManager;
}
@Bean
public OAuth2AuthenticationProcessingFilter auth2AuthenticationProcessingFilter() throws Exception {
OAuth2AuthenticationProcessingFilter oAuth2AuthenticationProcessingFilter = new OAuth2AuthenticationProcessingFilter();
oAuth2AuthenticationProcessingFilter.setAuthenticationManager(auth2AuthenticationManager());
return oAuth2AuthenticationProcessingFilter;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
OAuth2AuthenticationEntryPoint oAuth2AuthenticationEntryPoint = new OAuth2AuthenticationEntryPoint();
oAuth2AuthenticationEntryPoint.setRealmName("realmName");
oAuth2AuthenticationEntryPoint.setTypeName("Basic");
oAuth2AuthenticationEntryPoint.setExceptionTranslator(webResponseExceptionTranslator());
http
.antMatcher("/**").httpBasic()
.authenticationEntryPoint(oAuth2AuthenticationEntryPoint)
.and().addFilterBefore(auth2AuthenticationProcessingFilter(), BasicAuthenticationFilter.class)
.authorizeRequests()
.antMatchers("/rest/womar/admin/**").hasRole("ADMIN")
.antMatchers("/rest/womar/**").hasRole("USER");
}
}
각도 요청 :
var config = {
params: {
grant_type: 'password',
username: login,
password: password
},
headers: {
Authorization: 'Basic ' + Base64.encode('secret-client' + ':' + 'secret')
}
};
$http.get("http://localhost:8080/oauth/token", config)
.success(function(data, status) {
$log.log('success');
$log.log(data);
$log.log(status);
})
.error(function(data, status) {
$log.log('error');
$log.log(data);
$log.log(status);
});
해결법
-
==============================
1.@EnableAuthorizationServer는 / oauth / token, / oauth / token_key 등의 엔드 포인트에 대한 http 보안 구성을 순서 0에서 추가합니다. 그러면 OPTIONS http 메소드에 대해서만 / oauth / token 엔드 포인트에 대한 http 보안 룰을 정의해야합니다. 더 높은 순서로.
@EnableAuthorizationServer는 / oauth / token, / oauth / token_key 등의 엔드 포인트에 대한 http 보안 구성을 순서 0에서 추가합니다. 그러면 OPTIONS http 메소드에 대해서만 / oauth / token 엔드 포인트에 대한 http 보안 룰을 정의해야합니다. 더 높은 순서로.
이 같은:
@Order(-1) @Configuration public class MyWebSecurity extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers(HttpMethod.OPTIONS, "/oauth/token").permitAll() } }
-
==============================
2.idursun이 제안한 솔루션을 사용하고있었습니다. OPTION 호출은 작동하기 시작했지만 Access-Control-Allow-Origin에는 여전히 문제가있었습니다.
idursun이 제안한 솔루션을 사용하고있었습니다. OPTION 호출은 작동하기 시작했지만 Access-Control-Allow-Origin에는 여전히 문제가있었습니다.
이 필터 구현은 확실히 나를 위해 작동했습니다.
독립 실행 형 스프링 OAuth2 JWT 권한 부여 서버 + CORS
-
==============================
3.방금 추가합니다.
방금 추가합니다.
...에서
봄의 지원 설정
나를 위해 일했다.
-
==============================
4.다음은 스프링 부트 2에서 작동합니다. 그렇지 않으면 다른 CORS 구성을 선택하지 않습니다.
다음은 스프링 부트 2에서 작동합니다. 그렇지 않으면 다른 CORS 구성을 선택하지 않습니다.
@Configuration @EnableAuthorizationServer public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { // this is a Spring ConfigurationProperty use any way to get the CORS values @Autowired private CorsProperties corsProperties; // other things //... @Override public void configure( AuthorizationServerEndpointsConfigurer endpoints) { endpoints .tokenStore(tokenStore()) .authenticationManager(authenticationManager); if (corsProperties.getAllowedOrigins() != null) { Map<String, CorsConfiguration> corsConfigMap = new HashMap<>(); Arrays.asList(corsProperties.getAllowedOrigins().split(",")).stream() .filter(StringUtils::isNotBlank).forEach(s -> { CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); config.addAllowedOrigin(s.trim()); if (corsProperties.getAllowedMethods() != null) { config.setAllowedMethods(Arrays.asList(corsProperties.getAllowedMethods().split(","))); } if (corsProperties.getAllowedHeaders() != null) { config.setAllowedHeaders(Arrays.asList(corsProperties.getAllowedHeaders().split(","))); } // here the /oauth/token is used corsConfigMap.put("/oauth/token", config); }); endpoints.getFrameworkEndpointHandlerMapping() .setCorsConfigurations(corsConfigMap); } } }
OPTIONS 요청에 대한 이미 언급 된 허용치 :
@Order(-1) @Configuration public class MyWebSecurity extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http authorizeRequests() .antMatchers("/**/oauth/token").permitAll() .and().httpBasic().realmName(securityRealm) // would throw a 403 otherwise .and().csrf().disable() // optional, but with a token a sesion is not needed anymore .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); } }
-
==============================
5.Spring-Boot 1.4.7.RELEASE와 동일한 문제점
Spring-Boot 1.4.7.RELEASE와 동일한 문제점
내 WebSecurityConfigurerAdapter가 SecurityProperties.ACCESS_OVERRIDE_ORDER를 사용하여 선택한 대답이 작동하지 않았습니다.
@Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) @Order(SecurityProperties.ACCESS_OVERRIDE_ORDER) public class AuthServerSecurityConfig extends WebSecurityConfigurerAdapter
따라서 이전 순서로 다음 필터 구성을 추가했습니다.
@Bean public FilterRegistrationBean corsFilter() { FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(corsConfigurationSource())); bean.setOrder(SecurityProperties.DEFAULT_FILTER_ORDER); return bean; } @Bean public CorsConfigurationSource corsConfigurationSource() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); config.addAllowedOrigin("*"); config.addAllowedHeader("*"); config.addAllowedMethod("*"); source.registerCorsConfiguration("/**", config); return source; }
그리고 일이 끝났어.
주 : 아래와 같이 @Order (SecurityProperties.DEFAULT_FILTER_ORDER) 주석이있는 javax.servlet.Filter bean을 사용하면 동일한 결과를 얻을 수 있습니다.
@Component @Order(SecurityProperties.DEFAULT_FILTER_ORDER) public class CorsFilter implements Filter { @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { final HttpServletResponse response = (HttpServletResponse) res; response.setHeader("Access-Control-Allow-Origin" , "*" ); response.setHeader("Access-Control-Allow-Methods" , "POST, PUT, GET, OPTIONS, DELETE" ); response.setHeader("Access-Control-Allow-Headers" , "Authorization, Content-Type" ); response.setHeader("Access-Control-Max-Age" , "3600" ); if("OPTIONS".equalsIgnoreCase(((HttpServletRequest) req).getMethod())) { response.setStatus(HttpServletResponse.SC_OK); } else { chain.doFilter(req, res); } } // ... }
from https://stackoverflow.com/questions/25136532/allow-options-http-method-for-oauth-token-request by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] 봄과 XML 및 자바 구성을 혼합 (0) | 2018.12.30 |
---|---|
[SPRING] Spring MVC에서 뷰를 렌더링 할 때 발생하는 예외를 처리하는 방법은 무엇입니까? (0) | 2018.12.30 |
[SPRING] 봄에 abstract = "true"가 의미하는 것은 무엇입니까? (0) | 2018.12.30 |
[SPRING] Spring .properties 파일 : 요소를 배열로 가져 오기 (0) | 2018.12.30 |
[SPRING] LDAP : 연결 세부 정보로 사용자를 인증하는 방법 (0) | 2018.12.30 |