我正在使用 Spring 安全策略,需要全局角色 SUPER 的帮助,当令牌拥有时,该角色必须绕过端点上的所有
@PreAuthorize
。这是一个端点示例:
@GetMapping
@PreAuthorize("(hasAuthority('DOMAIN_FIND_ALL'))")
public ResponseEntity<ResponseDTO<List<DomainDTO>>> findAll() {
return ResponseEntity.ok().body(domainService.findAll());
}
我发现我的全球角色的工作方式是这样的
@GetMapping
@PreAuthorize("(hasAuthority('DOMAIN_FIND_ALL') or (hasAuthority('SUPER'))")
public ResponseEntity<ResponseDTO<List<DomainDTO>>> findAll() {
return ResponseEntity.ok().body(domainService.findAll());
}
但是实现应用程序的每个端点都太长了
(hasAuthority('SUPER')
,所以我正在寻找一种以全局方式配置它的方法,这样,如果令牌具有该角色,则允许所有端点。
我尝试过的:
@Override
public void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.otherStuffs..
.antMatchers("/**").authenticated()
.antMatchers("/**").hasRole("SUPER");
}
但这不起作用。有人对此有什么想法吗?
更详细的解释,请看下面的链接(主要是第6节)。用作我回复基础的代码是:
以下代码对我有用:
@Override
public void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.otherStuffs..
.antMatchers("/**").authenticated(); // hasRole("SUPER") isn't require
}
覆盖默认的
MethodSecurityExpressionOperations
界面:
public class MySecurityExpressionRoot implements MethodSecurityExpressionOperations {
// Same properties than provided
// link for MySecurityExpressionRoot
...
public MySecurityExpressionRoot(Authentication authentication) {
if (authentication == null) {
throw new IllegalArgumentException("Authentication object cannot be null");
}
this.authentication = authentication;
}
// This is the ONLY change, as you can see the "SUPER" was added as allowed
@Override
public final boolean hasAuthority(String authority) {
return this.hasAnyAuthority(authority, "SUPER");
}
// Rest of the code is the same than provided
// link for MySecurityExpressionRoot
...
}
现在我们需要将上面的类添加到 Spring 配置中:
@Configuration // Required although not include in "source CustomMethodSecurityExpressionHandler" class
public class CustomMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler {
private final AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
@Override
protected MethodSecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication, MethodInvocation invocation) {
final MySecurityExpressionRoot root = new MySecurityExpressionRoot(authentication);
root.setPermissionEvaluator(getPermissionEvaluator());
root.setTrustResolver(this.trustResolver);
root.setRoleHierarchy(getRoleHierarchy());
return root;
}
}
现在您可以使用以下虚拟
GET
端点来验证它:
@GetMapping("/add-new-user")
@PreAuthorize("hasAuthority('ADMIN')")
public ResponseEntity<String> addNewUser() {
return new ResponseEntity("[add-new-user] Testing purpose", OK);
}
任何具有:
ADMIN
或 SUPER
角色的用户都可以访问它。
好吧,这是一个棘手的方法:
org.springframework.security.authorization.method
。PreAuthorizeAuthorizationManager
,复制spring源代码,这将覆盖spring源代码。AuthorizationDecision
override fun check(authentication: Supplier<Authentication>, mi: MethodInvocation): AuthorizationDecision? {
// Bypass super admin role, add your own logic here.
authentication.get().takeIf { it.isAuthenticated }?.let { it.principal as? LoginUserDetails }
?.takeIf { it.type === UserType.BACKEND_USER && it.roles.contains("super-admin") }
?.let { AuthorizationDecision(true) }
?.also { return it }
// below is spring security original code...
val attribute = registry.getAttribute(mi)
if (attribute === ExpressionAttribute.NULL_ATTRIBUTE) {
return null
}
val ctx = registry.expressionHandler.createEvaluationContext(authentication, mi)
return ExpressionUtils.evaluate(attribute.expression, ctx) as AuthorizationDecision
}