✨ 使用自带的校验方法,完成权限表达式解析
This commit is contained in:
parent
d8a34d7fa6
commit
1940b29247
|
@ -1127,14 +1127,55 @@ public Result<String> lowerUser(String name) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 使用自定义授权管理器
|
### 使用自定义授权管理器实现自定义权限校验
|
||||||
|
|
||||||
在实际开发中对于SpringSecurity提供的两个权限校验注解`@PreAuthorize`和`@PostAuthorize`,需要对这两个进行覆盖或者改造,需要实现两个`AuthorizationManager<T>`。
|
在实际开发中对于SpringSecurity提供的两个权限校验注解`@PreAuthorize`和`@PostAuthorize`,需要对这两个进行覆盖或者改造,需要实现两个`AuthorizationManager<T>`。
|
||||||
|
|
||||||
实现完成后需要显式的在配置中禁用原先的内容。
|
实现完成后需要显式的在配置中禁用原先的内容。
|
||||||
|
|
||||||
|
#### 前置条件
|
||||||
|
|
||||||
|
为了做一个较为通用看起来比较规范,写了一个配置类,可以在Spring配置文件中进行配置。
|
||||||
|
|
||||||
|
```java
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Configuration
|
||||||
|
@ConfigurationProperties(prefix = "security-path")
|
||||||
|
@Schema(name = "SecurityPathsProperties对象", description = "路径忽略和认证")
|
||||||
|
public class SecurityConfigProperties {
|
||||||
|
|
||||||
|
@Schema(name = "noAuthPaths", description = "不用认证的路径")
|
||||||
|
public List<String> noAuthPaths;
|
||||||
|
|
||||||
|
@Schema(name = "securedPaths", description = "需要认证的路径")
|
||||||
|
public List<String> securedPaths;
|
||||||
|
|
||||||
|
@Schema(name = "允许的角色或权限", description = "允许的角色或权限")
|
||||||
|
public List<String> adminAuthorities;
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
之后在配置文件中指定哪些可以放行的角色或权限。
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
security-path:
|
||||||
|
# 配置放行的角色或权限
|
||||||
|
admin-authorities:
|
||||||
|
- "ADMIN"
|
||||||
|
```
|
||||||
|
|
||||||
#### 1. 实现前置
|
#### 1. 实现前置
|
||||||
|
|
||||||
|
**方式一:正则表达式**
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
>
|
||||||
|
> 这种实现方式是要判断传入的内容是否和预期一致,这里使用了正则,但并不是很优雅。
|
||||||
|
>
|
||||||
|
> 有些违背了Spring设计哲学。
|
||||||
|
|
||||||
在方法中写入自己的校验逻辑。
|
在方法中写入自己的校验逻辑。
|
||||||
|
|
||||||
`MethodInvocation`类型是执行方法之前相当于是一个反射,可以获取到当前方法上的注解、方法名称、当前类等。
|
`MethodInvocation`类型是执行方法之前相当于是一个反射,可以获取到当前方法上的注解、方法名称、当前类等。
|
||||||
|
@ -1223,6 +1264,90 @@ public class PreAuthorizationManager implements AuthorizationManager<MethodInvoc
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**方式二:自带的**
|
||||||
|
|
||||||
|
需要重新设置配置:
|
||||||
|
|
||||||
|
```java
|
||||||
|
@Configuration
|
||||||
|
@EnableMethodSecurity(prePostEnabled = false)
|
||||||
|
public class AuthorizationManagerConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||||
|
public MethodSecurityExpressionHandler methodSecurityExpressionHandler() {
|
||||||
|
DefaultMethodSecurityExpressionHandler handler = new DefaultMethodSecurityExpressionHandler();
|
||||||
|
// // 可选配置---移除 ROLE_ 前缀
|
||||||
|
// handler.setDefaultRolePrefix("");
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||||
|
Advisor preAuthorize(PreAuthorizationManager manager) {
|
||||||
|
return AuthorizationManagerBeforeMethodInterceptor.preAuthorize(manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||||
|
Advisor postAuthorize(PostAuthorizationManager manager) {
|
||||||
|
return AuthorizationManagerAfterMethodInterceptor.postAuthorize(manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
实现
|
||||||
|
|
||||||
|
```java
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class PreAuthorizationManager implements AuthorizationManager<MethodInvocation> {
|
||||||
|
|
||||||
|
private final SecurityConfigProperties securityConfigProperties;
|
||||||
|
private final MethodSecurityExpressionHandler expressionHandler;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AuthorizationDecision check(Supplier<Authentication> authenticationSupplier, MethodInvocation methodInvocation) {
|
||||||
|
|
||||||
|
// 获取方法上的@PreAuthorize注解
|
||||||
|
PreAuthorize preAuthorize = AnnotationUtils.findAnnotation(methodInvocation.getMethod(), PreAuthorize.class);
|
||||||
|
|
||||||
|
if (preAuthorize == null) {
|
||||||
|
// 没有注解默认放行
|
||||||
|
return new AuthorizationDecision(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用Spring的表达式解析器
|
||||||
|
EvaluationContext ctx = expressionHandler.createEvaluationContext(authenticationSupplier.get(), methodInvocation);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 解析表达式并获取结果
|
||||||
|
Expression expression = expressionHandler.getExpressionParser().parseExpression(preAuthorize.value());
|
||||||
|
|
||||||
|
boolean granted = Boolean.TRUE.equals(expression.getValue(ctx, Boolean.class));
|
||||||
|
|
||||||
|
// 如果表达式不通过,检查是否是admin
|
||||||
|
if (!granted) {
|
||||||
|
granted = isAdmin(authenticationSupplier.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
return new AuthorizationDecision(granted);
|
||||||
|
} catch (EvaluationException | ParseException e) {
|
||||||
|
return new AuthorizationDecision(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isAdmin(Authentication authentication) {
|
||||||
|
return securityConfigProperties.getAdminAuthorities().stream()
|
||||||
|
.anyMatch(auth -> authentication.getAuthorities().stream()
|
||||||
|
.map(GrantedAuthority::getAuthority)
|
||||||
|
.anyMatch(ga -> ga.equals(auth)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
#### 2. 实现后置
|
#### 2. 实现后置
|
||||||
|
|
||||||
```java
|
```java
|
||||||
|
|
|
@ -13,7 +13,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||||
@RequestMapping("/api/security/pre")
|
@RequestMapping("/api/security/pre")
|
||||||
public class SecurityPreAuthorizationController {
|
public class SecurityPreAuthorizationController {
|
||||||
|
|
||||||
@PreAuthorize("hasPermission('role::read')")
|
@PreAuthorize("hasAuthority('role::read')")
|
||||||
@Operation(summary = "拥有 role:read 的角色可以访问", description = "当前用户拥有 role:read 角色可以访问这个接口")
|
@Operation(summary = "拥有 role:read 的角色可以访问", description = "当前用户拥有 role:read 角色可以访问这个接口")
|
||||||
@GetMapping("role-user")
|
@GetMapping("role-user")
|
||||||
public Result<String> roleUser() {
|
public Result<String> roleUser() {
|
||||||
|
@ -28,7 +28,7 @@ public class SecurityPreAuthorizationController {
|
||||||
return Result.success(data);
|
return Result.success(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PreAuthorize("'admin'")
|
@PreAuthorize("hasAnyRole('admin') || hasAuthority('USER')")
|
||||||
@Operation(summary = "拥有 admin 的角色可以访问", description = "当前用户拥有 admin 角色可以访问这个接口")
|
@Operation(summary = "拥有 admin 的角色可以访问", description = "当前用户拥有 admin 角色可以访问这个接口")
|
||||||
@GetMapping("lower-admin")
|
@GetMapping("lower-admin")
|
||||||
public Result<String> lowerAdmin() {
|
public Result<String> lowerAdmin() {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package com.spring.step3.security.annotation.programmatically;
|
package com.spring.step3.security.annotation;
|
||||||
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
package com.spring.step3.security.manger;
|
package com.spring.step3.security.config;
|
||||||
|
|
||||||
|
import com.spring.step3.security.manger.demo1.PostAuthorizationManager;
|
||||||
|
import com.spring.step3.security.manger.demo2.PreAuthorizationManager;
|
||||||
import org.springframework.aop.Advisor;
|
import org.springframework.aop.Advisor;
|
||||||
import org.springframework.beans.factory.config.BeanDefinition;
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Role;
|
import org.springframework.context.annotation.Role;
|
||||||
|
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
|
||||||
|
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
|
||||||
import org.springframework.security.authorization.method.AuthorizationManagerAfterMethodInterceptor;
|
import org.springframework.security.authorization.method.AuthorizationManagerAfterMethodInterceptor;
|
||||||
import org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor;
|
import org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor;
|
||||||
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
||||||
|
@ -13,6 +17,16 @@ import org.springframework.security.config.annotation.method.configuration.Enabl
|
||||||
@EnableMethodSecurity(prePostEnabled = false)
|
@EnableMethodSecurity(prePostEnabled = false)
|
||||||
public class AuthorizationManagerConfiguration {
|
public class AuthorizationManagerConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||||
|
public MethodSecurityExpressionHandler methodSecurityExpressionHandler() {
|
||||||
|
DefaultMethodSecurityExpressionHandler handler = new DefaultMethodSecurityExpressionHandler();
|
||||||
|
// // 可选配置---移除 ROLE_ 前缀
|
||||||
|
// handler.setDefaultRolePrefix("");
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||||
Advisor preAuthorize(PreAuthorizationManager manager) {
|
Advisor preAuthorize(PreAuthorizationManager manager) {
|
|
@ -1,9 +1,9 @@
|
||||||
package com.spring.step3.security.config;
|
package com.spring.step3.security.config;
|
||||||
|
|
||||||
|
import com.spring.step3.security.config.properties.SecurityConfigProperties;
|
||||||
import com.spring.step3.security.filter.JwtAuthenticationFilter;
|
import com.spring.step3.security.filter.JwtAuthenticationFilter;
|
||||||
import com.spring.step3.security.handler.SecurityAccessDeniedHandler;
|
import com.spring.step3.security.handler.SecurityAccessDeniedHandler;
|
||||||
import com.spring.step3.security.handler.SecurityAuthenticationEntryPoint;
|
import com.spring.step3.security.handler.SecurityAuthenticationEntryPoint;
|
||||||
import com.spring.step3.security.properties.SecurityConfigProperties;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package com.spring.step3.security.properties;
|
package com.spring.step3.security.config.properties;
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
|
@ -4,8 +4,8 @@ import com.spring.step3.config.context.BaseContext;
|
||||||
import com.spring.step3.domain.vo.result.ResultCodeEnum;
|
import com.spring.step3.domain.vo.result.ResultCodeEnum;
|
||||||
import com.spring.step3.exception.AuthenticSecurityException;
|
import com.spring.step3.exception.AuthenticSecurityException;
|
||||||
import com.spring.step3.exception.MyAuthenticationException;
|
import com.spring.step3.exception.MyAuthenticationException;
|
||||||
|
import com.spring.step3.security.config.properties.SecurityConfigProperties;
|
||||||
import com.spring.step3.security.handler.SecurityAuthenticationEntryPoint;
|
import com.spring.step3.security.handler.SecurityAuthenticationEntryPoint;
|
||||||
import com.spring.step3.security.properties.SecurityConfigProperties;
|
|
||||||
import com.spring.step3.security.service.DbUserDetailService;
|
import com.spring.step3.security.service.DbUserDetailService;
|
||||||
import com.spring.step3.security.service.JwtTokenService;
|
import com.spring.step3.security.service.JwtTokenService;
|
||||||
import jakarta.servlet.FilterChain;
|
import jakarta.servlet.FilterChain;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package com.spring.step3.security.manger;
|
package com.spring.step3.security.manger.demo1;
|
||||||
|
|
||||||
import com.spring.step3.domain.vo.result.Result;
|
import com.spring.step3.domain.vo.result.Result;
|
||||||
import com.spring.step3.security.properties.SecurityConfigProperties;
|
import com.spring.step3.security.config.properties.SecurityConfigProperties;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.security.authorization.AuthorizationDecision;
|
import org.springframework.security.authorization.AuthorizationDecision;
|
||||||
import org.springframework.security.authorization.AuthorizationManager;
|
import org.springframework.security.authorization.AuthorizationManager;
|
||||||
|
|
|
@ -1,106 +0,0 @@
|
||||||
package com.spring.step3.security.manger;
|
|
||||||
|
|
||||||
import com.spring.step3.security.properties.SecurityConfigProperties;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.aopalliance.intercept.MethodInvocation;
|
|
||||||
import org.springframework.core.annotation.AnnotationUtils;
|
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.security.authorization.AuthorizationDecision;
|
|
||||||
import org.springframework.security.authorization.AuthorizationManager;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理方法调用前的授权检查
|
|
||||||
* check()方法接收的是MethodInvocation对象,包含即将执行的方法调用信息
|
|
||||||
* 用于决定是否允许执行某个方法
|
|
||||||
* 这是传统的"前置授权"模式
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class PreAuthorizationManager implements AuthorizationManager<MethodInvocation> {
|
|
||||||
|
|
||||||
private final SecurityConfigProperties securityConfigProperties;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AuthorizationDecision check(Supplier<Authentication> authenticationSupplier, MethodInvocation methodInvocation) {
|
|
||||||
Authentication authentication = authenticationSupplier.get();
|
|
||||||
|
|
||||||
// 如果方法有 @PreAuthorize 注解,会先到这里
|
|
||||||
if (authentication == null || !authentication.isAuthenticated()) {
|
|
||||||
return new AuthorizationDecision(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查权限
|
|
||||||
boolean granted = hasPermission(authentication, methodInvocation);
|
|
||||||
return new AuthorizationDecision(granted);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean hasPermission(Authentication authentication, MethodInvocation methodInvocation) {
|
|
||||||
PreAuthorize preAuthorize = AnnotationUtils.findAnnotation(methodInvocation.getMethod(), PreAuthorize.class);
|
|
||||||
if (preAuthorize == null) {
|
|
||||||
return true; // 没有注解默认放行
|
|
||||||
}
|
|
||||||
|
|
||||||
String expression = preAuthorize.value();
|
|
||||||
// 解析表达式中的权限要求
|
|
||||||
List<String> requiredAuthorities = extractAuthoritiesFromExpression(expression);
|
|
||||||
|
|
||||||
// 获取配置的admin权限
|
|
||||||
List<String> adminAuthorities = securityConfigProperties.getAdminAuthorities();
|
|
||||||
|
|
||||||
return authentication.getAuthorities().stream()
|
|
||||||
.map(GrantedAuthority::getAuthority)
|
|
||||||
.anyMatch(auth ->
|
|
||||||
adminAuthorities.contains(auth) ||
|
|
||||||
requiredAuthorities.contains(auth)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<String> extractAuthoritiesFromExpression(String expression) {
|
|
||||||
List<String> authorities = new ArrayList<>();
|
|
||||||
|
|
||||||
// 处理 hasAuthority('permission') 格式
|
|
||||||
Pattern hasAuthorityPattern = Pattern.compile("hasAuthority\\('([^']+)'\\)");
|
|
||||||
Matcher hasAuthorityMatcher = hasAuthorityPattern.matcher(expression);
|
|
||||||
while (hasAuthorityMatcher.find()) {
|
|
||||||
authorities.add(hasAuthorityMatcher.group(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理 hasRole('ROLE_XXX') 格式 (Spring Security 会自动添加 ROLE_ 前缀)
|
|
||||||
Pattern hasRolePattern = Pattern.compile("hasRole\\('([^']+)'\\)");
|
|
||||||
Matcher hasRoleMatcher = hasRolePattern.matcher(expression);
|
|
||||||
while (hasRoleMatcher.find()) {
|
|
||||||
authorities.add(hasRoleMatcher.group(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理 hasAnyAuthority('perm1','perm2') 格式
|
|
||||||
Pattern hasAnyAuthorityPattern = Pattern.compile("hasAnyAuthority\\(([^)]+)\\)");
|
|
||||||
Matcher hasAnyAuthorityMatcher = hasAnyAuthorityPattern.matcher(expression);
|
|
||||||
while (hasAnyAuthorityMatcher.find()) {
|
|
||||||
String[] perms = hasAnyAuthorityMatcher.group(1).split(",");
|
|
||||||
for (String perm : perms) {
|
|
||||||
authorities.add(perm.trim().replaceAll("'", ""));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理 hasAnyRole('role1','role2') 格式
|
|
||||||
Pattern hasAnyRolePattern = Pattern.compile("hasAnyRole\\(([^)]+)\\)");
|
|
||||||
Matcher hasAnyRoleMatcher = hasAnyRolePattern.matcher(expression);
|
|
||||||
while (hasAnyRoleMatcher.find()) {
|
|
||||||
String[] roles = hasAnyRoleMatcher.group(1).split(",");
|
|
||||||
for (String role : roles) {
|
|
||||||
authorities.add(role.trim().replaceAll("'", ""));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return authorities;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,106 @@
|
||||||
|
// package com.spring.step3.security.manger.demo1;
|
||||||
|
//
|
||||||
|
// import com.spring.step3.security.properties.SecurityConfigProperties;
|
||||||
|
// import lombok.RequiredArgsConstructor;
|
||||||
|
// import org.aopalliance.intercept.MethodInvocation;
|
||||||
|
// import org.springframework.core.annotation.AnnotationUtils;
|
||||||
|
// import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
// import org.springframework.security.authorization.AuthorizationDecision;
|
||||||
|
// import org.springframework.security.authorization.AuthorizationManager;
|
||||||
|
// import org.springframework.security.core.Authentication;
|
||||||
|
// import org.springframework.security.core.GrantedAuthority;
|
||||||
|
// import org.springframework.stereotype.Component;
|
||||||
|
//
|
||||||
|
// import java.util.ArrayList;
|
||||||
|
// import java.util.List;
|
||||||
|
// import java.util.function.Supplier;
|
||||||
|
// import java.util.regex.Matcher;
|
||||||
|
// import java.util.regex.Pattern;
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 处理方法调用前的授权检查
|
||||||
|
// * check()方法接收的是MethodInvocation对象,包含即将执行的方法调用信息
|
||||||
|
// * 用于决定是否允许执行某个方法
|
||||||
|
// * 这是传统的"前置授权"模式
|
||||||
|
// */
|
||||||
|
// @Component
|
||||||
|
// @RequiredArgsConstructor
|
||||||
|
// public class PreAuthorizationManager implements AuthorizationManager<MethodInvocation> {
|
||||||
|
//
|
||||||
|
// private final SecurityConfigProperties securityConfigProperties;
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public AuthorizationDecision check(Supplier<Authentication> authenticationSupplier, MethodInvocation methodInvocation) {
|
||||||
|
// Authentication authentication = authenticationSupplier.get();
|
||||||
|
//
|
||||||
|
// // 如果方法有 @PreAuthorize 注解,会先到这里
|
||||||
|
// if (authentication == null || !authentication.isAuthenticated()) {
|
||||||
|
// return new AuthorizationDecision(false);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 检查权限
|
||||||
|
// boolean granted = hasPermission(authentication, methodInvocation);
|
||||||
|
// return new AuthorizationDecision(granted);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private boolean hasPermission(Authentication authentication, MethodInvocation methodInvocation) {
|
||||||
|
// PreAuthorize preAuthorize = AnnotationUtils.findAnnotation(methodInvocation.getMethod(), PreAuthorize.class);
|
||||||
|
// if (preAuthorize == null) {
|
||||||
|
// return true; // 没有注解默认放行
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// String expression = preAuthorize.value();
|
||||||
|
// // 解析表达式中的权限要求
|
||||||
|
// List<String> requiredAuthorities = extractAuthoritiesFromExpression(expression);
|
||||||
|
//
|
||||||
|
// // 获取配置的admin权限
|
||||||
|
// List<String> adminAuthorities = securityConfigProperties.getAdminAuthorities();
|
||||||
|
//
|
||||||
|
// return authentication.getAuthorities().stream()
|
||||||
|
// .map(GrantedAuthority::getAuthority)
|
||||||
|
// .anyMatch(auth ->
|
||||||
|
// adminAuthorities.contains(auth) ||
|
||||||
|
// requiredAuthorities.contains(auth)
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private List<String> extractAuthoritiesFromExpression(String expression) {
|
||||||
|
// List<String> authorities = new ArrayList<>();
|
||||||
|
//
|
||||||
|
// // 处理 hasAuthority('permission') 格式
|
||||||
|
// Pattern hasAuthorityPattern = Pattern.compile("hasAuthority\\('([^']+)'\\)");
|
||||||
|
// Matcher hasAuthorityMatcher = hasAuthorityPattern.matcher(expression);
|
||||||
|
// while (hasAuthorityMatcher.find()) {
|
||||||
|
// authorities.add(hasAuthorityMatcher.group(1));
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 处理 hasRole('ROLE_XXX') 格式 (Spring Security 会自动添加 ROLE_ 前缀)
|
||||||
|
// Pattern hasRolePattern = Pattern.compile("hasRole\\('([^']+)'\\)");
|
||||||
|
// Matcher hasRoleMatcher = hasRolePattern.matcher(expression);
|
||||||
|
// while (hasRoleMatcher.find()) {
|
||||||
|
// authorities.add(hasRoleMatcher.group(1));
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 处理 hasAnyAuthority('perm1','perm2') 格式
|
||||||
|
// Pattern hasAnyAuthorityPattern = Pattern.compile("hasAnyAuthority\\(([^)]+)\\)");
|
||||||
|
// Matcher hasAnyAuthorityMatcher = hasAnyAuthorityPattern.matcher(expression);
|
||||||
|
// while (hasAnyAuthorityMatcher.find()) {
|
||||||
|
// String[] perms = hasAnyAuthorityMatcher.group(1).split(",");
|
||||||
|
// for (String perm : perms) {
|
||||||
|
// authorities.add(perm.trim().replaceAll("'", ""));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 处理 hasAnyRole('role1','role2') 格式
|
||||||
|
// Pattern hasAnyRolePattern = Pattern.compile("hasAnyRole\\(([^)]+)\\)");
|
||||||
|
// Matcher hasAnyRoleMatcher = hasAnyRolePattern.matcher(expression);
|
||||||
|
// while (hasAnyRoleMatcher.find()) {
|
||||||
|
// String[] roles = hasAnyRoleMatcher.group(1).split(",");
|
||||||
|
// for (String role : roles) {
|
||||||
|
// authorities.add(role.trim().replaceAll("'", ""));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return authorities;
|
||||||
|
// }
|
||||||
|
// }
|
|
@ -0,0 +1 @@
|
||||||
|
这里是使用正则实现,看起来并不优雅,有些违反Spring的设计哲学,但是效果可以实现。
|
|
@ -0,0 +1,65 @@
|
||||||
|
package com.spring.step3.security.manger.demo2;
|
||||||
|
|
||||||
|
import com.spring.step3.security.config.properties.SecurityConfigProperties;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.aopalliance.intercept.MethodInvocation;
|
||||||
|
import org.springframework.core.annotation.AnnotationUtils;
|
||||||
|
import org.springframework.expression.EvaluationContext;
|
||||||
|
import org.springframework.expression.EvaluationException;
|
||||||
|
import org.springframework.expression.Expression;
|
||||||
|
import org.springframework.expression.ParseException;
|
||||||
|
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.security.authorization.AuthorizationDecision;
|
||||||
|
import org.springframework.security.authorization.AuthorizationManager;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class PreAuthorizationManager implements AuthorizationManager<MethodInvocation> {
|
||||||
|
|
||||||
|
private final SecurityConfigProperties securityConfigProperties;
|
||||||
|
private final MethodSecurityExpressionHandler expressionHandler;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AuthorizationDecision check(Supplier<Authentication> authenticationSupplier, MethodInvocation methodInvocation) {
|
||||||
|
|
||||||
|
// 获取方法上的@PreAuthorize注解
|
||||||
|
PreAuthorize preAuthorize = AnnotationUtils.findAnnotation(methodInvocation.getMethod(), PreAuthorize.class);
|
||||||
|
|
||||||
|
if (preAuthorize == null) {
|
||||||
|
// 没有注解默认放行
|
||||||
|
return new AuthorizationDecision(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用Spring的表达式解析器
|
||||||
|
EvaluationContext ctx = expressionHandler.createEvaluationContext(authenticationSupplier.get(), methodInvocation);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 解析表达式并获取结果
|
||||||
|
Expression expression = expressionHandler.getExpressionParser().parseExpression(preAuthorize.value());
|
||||||
|
|
||||||
|
boolean granted = Boolean.TRUE.equals(expression.getValue(ctx, Boolean.class));
|
||||||
|
|
||||||
|
// 如果表达式不通过,检查是否是admin
|
||||||
|
if (!granted) {
|
||||||
|
granted = isAdmin(authenticationSupplier.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
return new AuthorizationDecision(granted);
|
||||||
|
} catch (EvaluationException | ParseException e) {
|
||||||
|
return new AuthorizationDecision(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isAdmin(Authentication authentication) {
|
||||||
|
return securityConfigProperties.getAdminAuthorities().stream()
|
||||||
|
.anyMatch(auth -> authentication.getAuthorities().stream()
|
||||||
|
.map(GrantedAuthority::getAuthority)
|
||||||
|
.anyMatch(ga -> ga.equals(auth)));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue