首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >自定义http安全配置以及OAuth2资源服务器

自定义http安全配置以及OAuth2资源服务器
EN

Stack Overflow用户
提问于 2016-03-26 09:53:24
回答 3查看 9.1K关注 0票数 5

我使用的Spring Security OAuth2具有非常基本的配置,运行良好。现在,我希望有一个单独的WebSecurityConfigurerAdapter,它包含自定义逻辑,该逻辑确定某人是否有权访问某些端点。然而,无论我尝试什么,它都不会被执行。下面是我的OAuth2配置和我对这个主题的发现。授权服务器:

代码语言:javascript
运行
复制
@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")...;
    }

}

资源服务器:

代码语言:javascript
运行
复制
@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中的规则不被执行)。

代码语言:javascript
运行
复制
@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的引用:

代码语言:javascript
运行
复制
@Component("security")
public class SecurityService {
    public boolean hasPermission(Authentication authentication, String param, String anotherParam) { ... }
}

我有一些集成测试来验证WebSecurityConfiguration中的自定义访问规则,它们可以工作(因为我跳过了那里的身份验证)。我希望能够使用资源服务器进行身份验证,然后使用我的自定义http安全性进行授权。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 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的实现,以保持与它们表达式的兼容性):

代码语言:javascript
运行
复制
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中的根。

代码语言:javascript
运行
复制
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(),以便将其设置为默认值:

代码语言:javascript
运行
复制
@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。

票数 2
EN

Stack Overflow用户

发布于 2017-02-16 09:14:16

在上面的代码中有两件事,第一,您应该给客户端分配一些权限。

这里有一些代码可以这样做:

在OAuth2AuthorizationServerConfig中,您应该更改这个

代码语言:javascript
运行
复制
clients.inMemory().withClient("CLIENT_NAME").authorities("ADMIN")....;

在比赛中你应该做

代码语言:javascript
运行
复制
 http.authorizeRequests().antMatchers(HttpMethod.GET, "/path/**")
    .hasAuthority("ADMIN");

也可以为安全方法/控制器添加注释。

代码语言:javascript
运行
复制
 @PreAuthorize("hasAuthority('ADMIN')")
票数 4
EN

Stack Overflow用户

发布于 2017-06-01 04:32:00

您可以将此解析为将OAuth2MethodSecurityExpressionHandler实例生成为bean。

相反,请这样做:

代码语言:javascript
运行
复制
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class OAuth2ResourceServerConfig extends GlobalMethodSecurityConfiguration {

        @Override
        protected MethodSecurityExpressionHandler createExpressionHandler() {
             return new OAuth2MethodSecurityExpressionHandler();
        }

        ....
}

这样做:

代码语言:javascript
运行
复制
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class OAuth2ResourceServerConfig extends GlobalMethodSecurityConfiguration {

        @Override
        protected MethodSecurityExpressionHandler createExpressionHandler() {
             return getOAuth2MethodSecurityExpressionHandler();
        }

        @Bean
        public OAuth2MethodSecurityExpressionHandler getOAuth2MethodSecurityExpressionHandler() {
             return new OAuth2MethodSecurityExpressionHandler();
        }

        ....
}

希望这会有其他人!

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36233910

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档