跳至主要内容

SpEL Expressions

在 ChatGPT 中打开

Spring 表达式语言(SpEL)提供了一种声明性方式,直接在注解中定义授权规则。@RouteAccess 注解使用 Spring Security 的内置授权函数评估 SpEL 表达式。

仅限 Spring Security

SpEL 表达式仅在使用 Spring 集成时可用。

@RouteAccess 注解接受一个 SpEL 表达式,该表达式评估为布尔值:

@Route("/admin/dashboard")
@RouteAccess("hasRole('ADMIN')")
public class AdminDashboardView extends Composite<Div> {
// 只有具有 ROLE_ADMIN 权限的用户才能访问
}

如果表达式评估为 true,则授予访问权限。如果为 false,用户将被重定向到访问拒绝页面。

内置安全功能​

Spring Security 通过 SecurityExpressionRoot 提供以下授权函数:

函数参数描述示例
hasRoleString role检查用户是否具有指定的角色(自动添加前缀ROLE_)hasRole('ADMIN') 匹配 ROLE_ADMIN
hasAnyRoleString... roles检查用户是否具有任何指定的角色hasAnyRole('ADMIN', 'MANAGER')
hasAuthorityString authority检查用户是否具有确切的权限字符串hasAuthority('REPORTS:READ')
hasAnyAuthorityString... authorities检查用户是否具有任何指定的权限hasAnyAuthority('REPORTS:READ', 'REPORTS:WRITE')
isAuthenticated无如果用户已认证,则返回 trueisAuthenticated()

示例​

// 角色检查
@Route("/admin")
@RouteAccess("hasRole('ADMIN')")
public class AdminView extends Composite<Div> { }

// 多个角色
@Route("/staff")
@RouteAccess("hasAnyRole('ADMIN', 'MANAGER', 'SUPERVISOR')")
public class StaffView extends Composite<Div> { }

// 权限检查
@Route("/reports")
@RouteAccess("hasAuthority('REPORTS:READ')")
public class ReportsView extends Composite<Div> { }

// 需要认证
@Route("/profile")
@RouteAccess("isAuthenticated()")
public class ProfileView extends Composite<Div> { }

组合条件​

使用布尔运算符(and、or、!)创建复杂的授权规则:

// 两个条件都需满足
@Route("/moderator/reports")
@RouteAccess("hasRole('MODERATOR') and hasAuthority('REPORTS:VIEW')")
public class ModeratorReportsView extends Composite<Div> { }

// 任一条件可授予访问权限
@Route("/support")
@RouteAccess("hasRole('ADMIN') or hasRole('SUPPORT')")
public class SupportView extends Composite<Div> { }

// 否定
@Route("/trial/features")
@RouteAccess("isAuthenticated() and !hasAuthority('PREMIUM')")
public class TrialFeaturesView extends Composite<Div> { }

// 复杂的多行表达式
@Route("/reports/advanced")
@RouteAccess("""
hasRole('ADMIN') or
(hasRole('ANALYST') and hasAuthority('REPORTS:ADVANCED'))
""")
public class AdvancedReportsView extends Composite<Div> { }

与其他注解组合​

@RouteAccess 与标准安全注解一起工作。评估器按优先顺序运行:

@Route("/team/admin")
@RolesAllowed("USER")
@RouteAccess("hasAuthority('TEAM:ADMIN')")
public class TeamAdminView extends Composite<Div> {
// 必须同时具有 USER 角色和 TEAM:ADMIN 权限
}

评估顺序:

  1. @RolesAllowed 评估器(优先级 5)验证 USER 角色
  2. 如果通过,则 @RouteAccess 评估器(优先级 6)评估 SpEL 表达式
  3. 如果通过,运行自定义评估器(优先级 10+)

自定义错误代码​

为访问拒绝提供有意义的错误代码:

@Route("/premium/features")
@RouteAccess(
value = "hasAuthority('PREMIUM')",
code = "PREMIUM_SUBSCRIPTION_REQUIRED"
)
public class PremiumFeaturesView extends Composite<Div> { }

code 参数在表达式评估为 false 时标识拒绝原因。

可用变量​

SpEL 表达式可以访问评估上下文中的以下变量:

变量类型描述
authenticationAuthenticationSpring Security 认证对象
principalObject当前认证的主体(通常是 UserDetails)
routeClassClass<? extends Component>正在访问的路由组件类
contextNavigationContextwebforJ 导航上下文
securityContextRouteSecurityContextwebforJ 路由安全上下文

使用变量的示例:

@Route("/admin")
@RouteAccess("authentication.name == 'superadmin'")
public class SuperAdminView extends Composite<Div> { }

何时使用 SpEL 与自定义评估器​

在以下情况下使用 @RouteAccess SpEL:

  • 授权纯粹基于角色或权限
  • 将内置安全功能与布尔逻辑组合
  • 不需要重用的路由特定规则

在以下情况下使用自定义评估器:

  • 授权依赖于路由参数(所有权检查)
  • 需要 Spring 服务集成的复杂业务逻辑
  • 多个路由之间可重用的授权模式
  • 文档化授权意图的自定义注解

请参阅 自定义评估器指南 以实现高级授权场景。