我正在使用$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安全性进行授权。
答案 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=3
(1.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();
}
....
}
希望这是其他人!