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

时间:2016-03-26 09:53:24

标签: spring spring-security spring-boot spring-security-oauth2

我正在使用$responseArray = $this->requestPaypal('SetExpressCheckout', array( 'RETURNURL' => 'http://returnUrl.fr/member/payment/confirm/validate/membership/'.$ref, 'CANCELURL' => 'http://cancelUrl.fr/member/payment/cancel', 'PAYMENTREQUEST_0_AMT' => $info['price'], # amount of transaction \ 'PAYMENTREQUEST_0_CURRENCYCODE' => 'EUR', # currency of transaction \ 'PAYMENTREQUEST_0_DESC0' => $info['description'], 'PAYMENTREQUEST_0_CUSTOM' => $info['time'], )); if ($responseArray instanceof RedirectResponse) { return $responseArray; } $token = $responseArray['TOKEN']; $payPalUrl = 'https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&useraction=commit&token='.$token.''; return $this->redirect($payPalUrl); ,其基本配置正常。我现在想要一个单独的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 - 带注释的bean创建EnableResourceServer WebSecurityConfigurerAdapter,它首先在每个请求上执行,用户成功通过身份验证/授权,但我的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(); } } 规则中的@security引用只是一个简单命名的Spring bean:

access

我有集成测试验证@Component("security") public class SecurityService { public boolean hasPermission(Authentication authentication, String param, String anotherParam) { ... } } 中的自定义访问规则并且它们有效(因为我在那里跳过了身份验证)。我希望能够仅使用资源服务器进行身份验证,然后使用我的自定义http安全性进行授权。

3 个答案:

答案 0 :(得分:4)

上述代码中有两件事,首先,您应该为客户端分配一些权限。

这里有一些代码:

在OAuth2AuthorizationServerConfig中

你应该改变这个

clients.inMemory().withClient("CLIENT_NAME").authorities("ADMIN")....;

在匹配器中你应该做

 http.authorizeRequests().antMatchers(HttpMethod.GET, "/path/**")
    .hasAuthority("ADMIN");

或者您可以为安全方法/控制器添加注释

 @PreAuthorize("hasAuthority('ADMIN')")

答案 1 :(得分:0)

假设您要使用oauth2,并且首先获得一个令牌并在您的API中使用它(使用Authorization Bearer [TOKEN]),您需要稍微更改一下逻辑以创建自定义表达式。

首先,如果您使用Spring引导1.5+,请考虑将以下属性添加到您的application.properties文件中:security.oauth2.resource.filter-order=31.5 release notes

现在,为了创建自定义过滤器,您需要了解一些组件。

默认情况下,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。

答案 2 :(得分:0)

您可以解决此问题,将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();
        }

        ....
}

希望这是其他人!