我使用的Spring Security OAuth2
具有非常基本的配置,运行良好。现在,我希望有一个单独的WebSecurityConfigurerAdapter
,它包含自定义逻辑,该逻辑确定某人是否有权访问某些端点。然而,无论我尝试什么,它都不会被执行。下面是我的OAuth2
配置和我对这个主题的发现。授权服务器:
@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private TokenStore tokenStore;
@Autowired
private AuthenticationManagerBuilder authenticationManager;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)throws Exception {
endpoints.authenticationManager(authentication -> authenticationManager.getOrBuild().authenticate(authentication)).tokenStore(tokenStore);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory().withClient("CLIENT_NAME")...;
}
}
资源服务器:
@Configuration
@EnableResourceServer
public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Autowired
private TokenStore tokenStore;
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated();
}
@Override
public void configure(final ResourceServerSecurityConfigurer resources) throws Exception {
resources.tokenStore(tokenStore);
}
}
到目前一切尚好。但是,当自定义WebSecurityConfigurerAdapter
开始工作时,我开始遇到问题。由于EnableResourceServer
-annotated bean使用Order(3)
创建了一个WebSecurityConfigurerAdapter
,它首先在每个请求上执行,因此用户被成功地验证/授权,但是我的WebSecurityConfiguration
中的自定义逻辑没有被执行。另一方面,如果我将WebSecurityConfiguration
设置为Order(2)
或更少,则执行自定义access
规则,但它总是表示它们来自匿名用户(因为@EnableResourceServer
创建的bean中的规则不被执行)。
@EnableWebSecurity
@Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/...");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.authorizeRequests().antMatchers(HttpMethod.GET, "/path/**")
.access("@security.hasPermission(authentication, 'SOME', 'VALUE')");
http.authorizeRequests().anyRequest().authenticated();
}
}
顺便提一下,@security
规则中的access
引用只是一个简单的名为Spring的引用:
@Component("security")
public class SecurityService {
public boolean hasPermission(Authentication authentication, String param, String anotherParam) { ... }
}
我有一些集成测试来验证WebSecurityConfiguration
中的自定义访问规则,它们可以工作(因为我跳过了那里的身份验证)。我希望能够使用资源服务器进行身份验证,然后使用我的自定义http安全性进行授权。
发布于 2017-02-20 18:15:40
假设您想要使用oauth2,并且首先获得一个令牌并在您的API中使用它(使用Authorization Bearer [TOKEN]
),那么您需要稍微修改您的逻辑,以便创建自定义表达式。
首先,如果使用spring 1.5+,请考虑将以下属性添加到application.properties文件中:security.oauth2.resource.filter-order=3
(1.5发行说明)
现在,为了创建自定义过滤器,您需要了解一些组件。
默认情况下,spring提供以下接口MethodSecurityExpressionHandler
,以处理安全表达式,所使用的实现是DefaultMethodSecurityExpressionHandler
。通常,您将使用OAuth2MethodSecurityExpressionHandler
为oauth2覆盖它,但让我们用自己的实现创建一个自定义的。
该类使用由MethodSecurityExpressionOperations
实现的接口SecurityExpressionRoot
来解析表达式。
首先,我们需要创建一个自定义MethodSecurityExpressionOperations
。在它的底部,您可以找到// custom logic methods
,它声明了自定义逻辑的开始(在上面是spring的实现,以保持与它们表达式的兼容性):
public class CustomMethodSecurityExpressionRoot extends SecurityExpressionRoot implements MethodSecurityExpressionOperations {
// Based on MethodSecurityExpressionRoot (class is package private in spring)
private Object filterObject;
private Object returnObject;
private Object target;
CustomMethodSecurityExpressionRoot(Authentication a) {
super(a);
}
public void setFilterObject(Object filterObject) {
this.filterObject = filterObject;
}
public Object getFilterObject() {
return filterObject;
}
public void setReturnObject(Object returnObject) {
this.returnObject = returnObject;
}
public Object getReturnObject() {
return returnObject;
}
/**
* Sets the "this" property for use in expressions. Typically this will be
* the "this" property of the {@code JoinPoint} representing the method
* invocation which is being protected.
*
* @param target
* the target object on which the method in is being invoked.
*/
void setThis(Object target) {
this.target = target;
}
public Object getThis() {
return target;
}
// custom logic methods
public boolean securityHasPermission(String param, String anotherParam) {
/* custom logic here */
}
接下来,我们需要将它设置为自定义MethodSecurityExpressionHandler
中的根。
public class CustomOAuth2MethodSecurityExpressionHandler extends OAuth2MethodSecurityExpressionHandler {
private final AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
@Override
protected MethodSecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication,
MethodInvocation invocation) {
final CustomMethodSecurityExpressionRoot root = new CustomMethodSecurityExpressionRoot(authentication);
root.setThis(invocation.getThis());
root.setPermissionEvaluator(getPermissionEvaluator());
root.setTrustResolver(this.trustResolver);
root.setRoleHierarchy(getRoleHierarchy());
return root;
}
}
接下来,我们需要将其设置为默认的MethodSecurityExpressionHandler
。我们可以通过扩展GlobalMethodSecurityConfiguration
来实现这一点。在该文件中,我们为自定义的@Bean
定义了一个新的MethodSecurityExpressionHandler
,并重写了createExpressionHandler()
,以便将其设置为默认值:
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class Oauth2GlobalMethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
return methodSecurityExpressionHandler();
}
@Bean
public MethodSecurityExpressionHandler methodSecurityExpressionHandler() {
return new CustomOAuth2MethodSecurityExpressionHandler();
}
现在,在控制器中,您可以添加@PreAuthorize("securityHasPermission('SOME', 'VALUE')")
来触发自定义逻辑。
您的自定义逻辑应该在CustomMethodSecurityExpressionRoot
中触发,并且您可以访问authentication
变量,因为它在初始化时已经注入到类中。在CustomOAuth2MethodSecurityExpressionHandler
中设置参数/bean时,还可以传递更多的参数/bean。
发布于 2017-02-16 09:14:16
在上面的代码中有两件事,第一,您应该给客户端分配一些权限。
这里有一些代码可以这样做:
在OAuth2AuthorizationServerConfig中,您应该更改这个
clients.inMemory().withClient("CLIENT_NAME").authorities("ADMIN")....;
在比赛中你应该做
http.authorizeRequests().antMatchers(HttpMethod.GET, "/path/**")
.hasAuthority("ADMIN");
也可以为安全方法/控制器添加注释。
@PreAuthorize("hasAuthority('ADMIN')")
发布于 2017-06-01 04:32:00
您可以将此解析为将OAuth2MethodSecurityExpressionHandler
实例生成为bean。
相反,请这样做:
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class OAuth2ResourceServerConfig extends GlobalMethodSecurityConfiguration {
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
return new OAuth2MethodSecurityExpressionHandler();
}
....
}
这样做:
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class OAuth2ResourceServerConfig extends GlobalMethodSecurityConfiguration {
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
return getOAuth2MethodSecurityExpressionHandler();
}
@Bean
public OAuth2MethodSecurityExpressionHandler getOAuth2MethodSecurityExpressionHandler() {
return new OAuth2MethodSecurityExpressionHandler();
}
....
}
希望这会有其他人!
https://stackoverflow.com/questions/36233910
复制相似问题