通过编程方式授权方法

This commit is contained in:
bunny 2025-07-20 00:59:17 +08:00
parent 1940b29247
commit c12807224e
4 changed files with 129 additions and 41 deletions

View File

@ -1083,8 +1083,43 @@ public class AuthTestController {
## 其余授权方式
### 前置条件
为了做一个较为通用看起来比较规范写了一个配置类可以在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"
```
### 通过编程方式授权方法
#### 简单使用
如果需要对权限做出自定义的需求,将传入参数作为判断权限条件,这会很有用,比如某些参数不可以传入,或者参数做权限校验等。
首先创建一个Spring组件包含自定义的授权逻辑
@ -1127,45 +1162,66 @@ public Result<String> lowerUser(String name) {
}
```
#### 进阶使用
> [!NOTE]
>
> 参考文档:[使用自定义的 `@Bean` 而不是对 `DefaultMethodSecurityExpressionHandler` 进行子类化](https://docs.spring.io/spring-security/reference/6.3/servlet/authorization/method-security.html#_use_a_custom_bean_instead_of_subclassing_defaultmethodsecurityexpressionhandler)
在上面可以大致了解到如何使用自定义的方式进行扩展,好处是可以简单易用。
可以对比下下面章节**【使用自定义授权管理器实现自定义权限校验】**实现哪个更符合你期望预期。
```java
@Component("auth")
@RequiredArgsConstructor
public class AuthorizationLogic {
private final SecurityConfigProperties securityConfigProperties;
/**
* 基本权限检查
*/
public boolean decide(String requiredAuthority) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || !authentication.isAuthenticated()) {
return false;
}
// 检查用户是否有指定权限或是admin
return hasAuthority(authentication, requiredAuthority) || isAdmin(authentication);
}
/**
* 检查是否是管理员
*/
public boolean isAdmin() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
return authentication != null && isAdmin(authentication);
}
private boolean isAdmin(Authentication authentication) {
return securityConfigProperties.getAdminAuthorities().stream()
.anyMatch(auth -> authentication.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.anyMatch(ga -> ga.equals(auth)));
}
private boolean hasAuthority(Authentication authentication, String authority) {
return authentication.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.anyMatch(auth -> auth.equals(authority));
}
}
```
### 使用自定义授权管理器实现自定义权限校验
在实际开发中对于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. 实现前置
**方式一:正则表达式**

View File

@ -3,7 +3,6 @@ package com.spring.step3.controller.test;
import com.spring.step3.domain.vo.result.Result;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.security.PermitAll;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
@ -17,8 +16,7 @@ import org.springframework.web.bind.annotation.RestController;
@PreAuthorize("hasAuthority('USER')")
public class SecurityProgrammaticallyController {
// @PreAuthorize("permitAll()")
@PermitAll
@PreAuthorize("permitAll()")
@Operation(summary = "拥有 USER 的角色可以访问", description = "当前用户拥有 USER 角色可以访问这个接口")
@GetMapping("upper-user")
public Result<String> upperUser() {

View File

@ -1,6 +1,5 @@
package com.spring.step3.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

View File

@ -1,14 +1,49 @@
package com.spring.step3.security.annotation;
import com.spring.step3.security.config.properties.SecurityConfigProperties;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
@Component("auth")
@RequiredArgsConstructor
public class AuthorizationLogic {
public boolean decide(String name) {
// 直接使用name的实现
// System.out.println(name);
return name.equalsIgnoreCase("user");
private final SecurityConfigProperties securityConfigProperties;
/**
* 基本权限检查
*/
public boolean decide(String requiredAuthority) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || !authentication.isAuthenticated()) {
return false;
}
// 检查用户是否有指定权限或是admin
boolean baseAuthority = authentication.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.anyMatch(auth -> auth.equals(requiredAuthority));
return baseAuthority || isAdmin(authentication);
}
/**
* 检查是否是管理员
*/
public boolean isAdmin() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
return authentication != null && isAdmin(authentication);
}
private boolean isAdmin(Authentication authentication) {
return securityConfigProperties.getAdminAuthorities().stream()
.anyMatch(auth -> authentication.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.anyMatch(ga -> ga.equals(auth)));
}
}