Mil*_*nov 5 spring spring-security spring-boot spring-security-oauth2
我正在使用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")...;
}
}
Run Code Online (Sandbox Code Playgroud)
资源服务器:
@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);
}
}
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好.当自定义WebSecurityConfigurerAdapter生效时,我开始遇到问题.由于EnableResourceServer-annotated bean创建了一个WebSecurityConfigurerAdapterwith,Order(3)它首先在每个请求上执行,用户被成功验证/授权,但我的自定义逻辑WebSecurityConfiguration没有被执行.另一方面,如果我设置WebSecurityConfiguration为Order(2)或者更少,access则执行自定义规则,但它总是说它们来自匿名用户(因为创建的bean中的规则@EnableResourceServer未被执行).
@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();
}
}
Run Code Online (Sandbox Code Playgroud)
正如旁注,规则中的@security引用access只是一个简单的命名Spring bean:
@Component("security")
public class SecurityService {
public boolean hasPermission(Authentication authentication, String param, String anotherParam) { ... }
}
Run Code Online (Sandbox Code Playgroud)
我有集成测试验证自定义访问规则WebSecurityConfiguration并且它们有效(因为我在那里跳过了身份验证).我希望能够仅使用资源服务器进行身份验证,然后使用我的自定义http安全性进行授权.
假设您想使用 oauth2,并且首先获得一个令牌并在 API 中使用它(使用Authorization Bearer [TOKEN]),您需要稍微更改一下逻辑才能创建自定义表达式。
首先,如果您使用 spring boot 1.5+,请考虑将以下属性添加到您的 application.properties 文件中:security.oauth2.resource.filter-order=3(1.5 发行说明)
现在,为了创建自定义过滤器,您需要了解一些组件。
默认情况下,spring 提供以下接口MethodSecurityExpressionHandler来处理安全表达式,使用的实现是DefaultMethodSecurityExpressionHandler. 通常您会使用 oauth2 覆盖它OAuth2MethodSecurityExpressionHandler,但让我们使用我们自己的实现创建一个自定义的。
此类使用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 */
}
Run Code Online (Sandbox Code Playgroud)
接下来,我们需要将其设置为自定义中的根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;
}
}
Run Code Online (Sandbox Code Playgroud)
接下来,我们需要将其设置为默认值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();
}
Run Code Online (Sandbox Code Playgroud)
现在,您可以在控制器中添加@PreAuthorize("securityHasPermission('SOME', 'VALUE')")以触发自定义逻辑
您的自定义逻辑应该被触发,CustomMethodSecurityExpressionRoot并且您可以访问authentication变量,因为它在初始化时已经注入到类中。您还可以在设置时传递更多参数/bean CustomOAuth2MethodSecurityExpressionHandler。
| 归档时间: |
|
| 查看次数: |
5243 次 |
| 最近记录: |