MethodExpressionAuthorizationManager 是 Spring Security 6.1 中用于基于表达式的方法授权管理器,它允许你使用 SpEL(Spring Expression Language)表达式定义复杂的访问控制规则。通过该管理器,你可以在方法调用前或调用后进行动态权限验证,支持访问用户信息、方法参数、返回值等上下文数据。
表达式支持,使用 SpEL 表达式定义授权规则,例如:
hasRole('admin'):验证用户角色
hasPermission(#user, 'delete'):基于对象实例的权限验证
@securityService.checkAccess(#user):调用自定义服务进行验证
注解驱动,支持 Spring Security 的注解:
@PreAuthorize:方法调用前验证
@PostAuthorize:方法调用后验证
@PreFilter:过滤方法参数
@PostFilter:过滤方法返回值
上下文访问,在表达式中访问:
authentication:当前用户认证信息
principal:用户主体对象
方法参数(通过名称或索引)
方法返回值(仅 @PostAuthorize)
下面是 Spring Security 中 SpEL 的核心表达式,如下表:
| 表达式 | 描述 |
|---|---|
| hasRole('ROLE') | 验证用户是否拥有指定角色(自动添加 ROLE_ 前缀) |
| hasAuthority('AUTH') | 验证用户是否拥有指定权限(不添加前缀) |
| principal | 访问当前用户主体对象 |
| authentication | 访问完整的 Authentication 对象 |
| permitAll | 允许所有访问 |
| denyAll | 拒绝所有访问 |
| isAnonymous() | 验证用户是否为匿名用户 |
| isAuthenticated() | 验证用户是否已认证 |
| isFullyAuthenticated() | 验证用户是否已完全认证(非记住我登录) |
| hasPermission(target, permission) | 使用 PermissionEvaluator 验证对象权限 |
下面是 MethodExpressionAuthorizationManager 类的源码:
package org.springframework.security.authorization.method;
import java.util.function.Supplier;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.security.access.expression.ExpressionUtils;
import org.springframework.security.access.expression.SecurityExpressionHandler;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.authorization.ExpressionAuthorizationDecision;
import org.springframework.security.core.Authentication;
import org.springframework.util.Assert;
/**
* 基于表达式的方法授权管理器
* 用于通过评估 SpEL 表达式来决定是否允许对方法的访问
* 支持在方法调用前进行权限检查
*/
public final class MethodExpressionAuthorizationManager implements AuthorizationManager<MethodInvocation> {
// 安全表达式处理器,用于解析和计算安全表达式
private SecurityExpressionHandler<MethodInvocation> expressionHandler = new DefaultMethodSecurityExpressionHandler();
// 待评估的 SpEL 表达式
private Expression expression;
/**
* 创建一个方法表达式授权管理器实例
* @param expressionString 要解析的原始表达式字符串,例如 "hasRole('ADMIN')"
*/
public MethodExpressionAuthorizationManager(String expressionString) {
Assert.hasText(expressionString, "expressionString cannot be empty");
// 使用表达式处理器解析表达式字符串
this.expression = this.expressionHandler.getExpressionParser().parseExpression(expressionString);
}
/**
* 设置用于解析和计算表达式的安全表达式处理器
* 默认使用 DefaultMethodSecurityExpressionHandler
* @param expressionHandler 要使用的表达式处理器
*/
public void setExpressionHandler(SecurityExpressionHandler<MethodInvocation> expressionHandler) {
Assert.notNull(expressionHandler, "expressionHandler cannot be null");
this.expressionHandler = expressionHandler;
// 使用新的表达式处理器重新解析表达式
this.expression = expressionHandler.getExpressionParser()
.parseExpression(this.expression.getExpressionString());
}
/**
* 通过评估表达式来决定是否允许访问
* @param authentication 当前用户的认证信息提供者
* @param context 方法调用上下文,包含方法信息和参数
* @return 基于表达式评估结果的授权决策
*/
@Override
public AuthorizationDecision check(Supplier<Authentication> authentication, MethodInvocation context) {
// 创建表达式评估上下文,将认证信息和方法调用上下文注入
EvaluationContext ctx = this.expressionHandler.createEvaluationContext(authentication, context);
// 评估表达式并获取布尔结果
boolean granted = ExpressionUtils.evaluateAsBoolean(this.expression, ctx);
// 创建包含表达式和评估结果的授权决策
return new ExpressionAuthorizationDecision(granted, this.expression);
}
@Override
public String toString() {
return "WebExpressionAuthorizationManager[expression='" + this.expression + "']";
}
}该注解方法调用前验证,如下:
// 仅 normal 角色可调用,且用户 ID 必须与当前登录用户 ID 相同或为 lisi
@PreAuthorize("hasRole('admin') || #username == authentication.principal.username")
@GetMapping("/hello2")
public String hello2(@RequestParam("username") String username) {
System.out.println("hello2() username=" + username);
return "Hello, Spring Security!";
}运行效果如下图:

该注解在方法调用后验证,如下:
// 返回后验证:仅用户所有者或 ADMIN 可查看敏感内容
@PostAuthorize("returnObject.username == authentication.principal.username || hasRole('admin')")
@GetMapping("/postAuthorize")
public UserModel postAuthorize() {
System.out.println("postAuthorize()");
UserModel userModel = new UserModel();
userModel.setId(2);
userModel.setUsername("lisi");
return userModel;
}上述代码运行效果如下图:

该注解用来参数值过滤,如下:
// 过滤输入参数:仅允许用户修改自己的消息
@PreFilter("filterObject.username == authentication.principal.username")
@PostMapping("/updateUsers")
public String updateMessages(@RequestBody List<UserModel> users) {
return JSONObject.toJSONString(users, JSONWriter.Feature.PrettyFormat);
}对应的 JS 代码如下:
function updateUsers() {
$.ajax({
url: '/updateUsers',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify([
{ "id": 1, "username": "zhangsan", "authorities":["menu:user:add", "menu:user:delete"] },
{ "id": 2, "username": "lisi", "authorities":["menu:user:add", "menu:user:delete"] }
]),
success: function(response) {
console.log('请求成功:', response);
},
error: function(xhr, status, error) {
console.error('请求失败:', error);
}
});
}运行上述示例,输出如下图:

该注解用来返回值过滤,如下:
// 过滤返回值:仅返回当前用户可见的消息
@PostFilter("filterObject.username == authentication.principal.username")
@GetMapping("/getUsers")
public List<UserModel> getMessages() {
return new ArrayList<>(){{
UserModel userModel1 = new UserModel();
userModel1.setId(1);
userModel1.setUsername("zhangsan");
userModel1.setAuthorities(Arrays.asList("menu:user:add", "menu:user:delete"));
add(userModel1);
UserModel userModel2 = new UserModel();
userModel2.setId(2);
userModel2.setUsername("lisi");
userModel2.setAuthorities(Arrays.asList("menu:user:add", "menu:user:delete"));
add(userModel2);
}};
}运行上述代码,效果如下图:

UserModel 类到定义如下:
package com.hxstrive.spring_security.model;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
import java.util.List;
import java.util.Set;
/**
* 用户实体
* @author hxstrive.com
*/
public class UserModel implements UserDetails {
// 用户ID
private int id;
// 用户名
private String username;
// 密码
private String password;
// 权限列表
private Collection<? extends GrantedAuthority> authorities; // 主要是这个
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
public void setAuthorities(List<String> authorities) {
this.authorities = AuthorityUtils.createAuthorityList(authorities);
}
//...
}注意,MethodExpressionAuthorizationManager 提供了强大的基于表达式的方法级授权能力,通过 SpEL 表达式可以实现复杂的动态访问控制。它是 Spring Security 中最灵活的授权方式,适合需要细粒度权限控制的企业级应用。