我试图为我的角度应用程序启用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);
});
答案 0 :(得分:39)
@EnableAuthorizationServer
正在为订单0添加/oauth/token
,/oauth/token_key
等端点的http安全配置。那么您应该为/oauth/token
定义一个http安全规则端点仅适用于处于更高阶的OPTIONS 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()
}
}
答案 1 :(得分:5)
我正在使用idursun提出的解决方案。 OPTION调用开始工作,但仍然存在Access-Control-Allow-Origin问题。
这个过滤器的实现最终对我有用:
答案 2 :(得分:3)
我只是添加
@Order(Ordered.HIGHEST_PRECEDENCE)
在
公共类OAuth2SecurityConfig扩展了WebSecurityConfigurerAdapter {....}
并配置spring的支持
@Bean
public CorsConfigurationSource corsConfigurationSource(){
CorsConfiguration配置=新CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList(&#34; &#34));
configuration.setAllowedMethods(Arrays.asList(&#34; &#34));
configuration.setAllowedHeaders(Arrays.asList(&#34; *&#34));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration(&#34; / **&#34;,configuration);
返回来源;
}
为我工作。
答案 3 :(得分:1)
以下适用于Spring Boot 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);
}
}
答案 4 :(得分:0)
与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;
}
它完成了工作。
注意:使用带有javax.servlet.Filter
注释的@Order(SecurityProperties.DEFAULT_FILTER_ORDER)
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);
}
}
// ...
}