在对Spring Security中自定义权限表达式的攻略之前,先简单介绍一下权限表达式的作用:
Spring Security中的权限表达式用于在方法调用或请求访问时,判断当前用户是否具有访问权限。Spring Security提供了很多默认的权限表达式,例如"hasRole()"和"hasAnyRole()"等。但是,我们有时需要根据不同的业务需求来自定义权限表达式。下面详细讲解如何在Spring Security中自定义权限表达式。
步骤一:继承SecurityExpressionRoot类
如果我们想要自定义权限表达式,就需要继承Spring Security中的SecurityExpressionRoot类。这个类中包含了Spring Security权限表达式的所有方法。
首先,我们需要建立一个自定义类,例如CustomSecurityExpressionRoot,继承SecurityExpressionRoot。创建完类以后,我们需要在实例化该类时,调用其父类SecurityExpressionRoot的构造方法。
public class CustomSecurityExpressionRoot extends SecurityExpressionRoot {
public CustomSecurityExpressionRoot(Authentication authentication) {
super(authentication);
}
// 自定义权限表达式
}
步骤二:添加自定义权限表达式的方法
在CustomSecurityExpressionRoot类中,我们需要添加自定义的权限表达式的方法。这些方法应该返回一个Boolean类型的值,根据当前用户是否具有该权限返回True或False。
例如,我们自定义一个权限表达式"hasPermission()",用于判断用户是否已登录并拥有特定权限。具体实现如下:
public class CustomSecurityExpressionRoot extends SecurityExpressionRoot {
// 代码省略...
public boolean hasPermission(String permission) {
Authentication authentication = getAuthentication();
if (authentication == null) {
return false;
}
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
Set<String> authorities = userDetails.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toSet());
return authorities.contains(permission);
}
}
上面的代码只是一个简单的示例,它只是检查用户是否有特定权限。您可以根据不同的业务需求,将权限检查更细致地定义。
步骤三:注册自定义的权限表达式
现在我们已经定义了自定义的权限表达式,但是Spring Security并不知道我们的自定义表达式。接下来,我们需要将自定义的权限表达式注册到Spring Security框架中。Spring Security提供了一个ExpressionParser类,用于解析权限表达式。我们需要将自己的表达式注册到ExpressionParser中。
在这里,我们需要创建一个CustomWebSecurityConfig对象,并且将项目所需的AuthenticationProvider以及自定义的CustomSecurityExpressionRoot Bean注入到该对象中。最后,在CustomWebSecurityConfig的configure(HttpSecurity http)方法中,使用http.authorizeRequests()方法调用access()方法,将自定义表达式与URL挂钩起来。
@Configuration
@EnableWebSecurity
public class CustomWebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomSecurityExpressionRoot customSecurityExpressionRoot;
@Autowired
private AuthenticationProvider authenticationProvider;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
// 自定义权限表达式挂钩
.antMatchers("/admin/**").access("@customSecurityExpressionRoot.hasPermission('ADMIN')")
// 其它权限接口
.antMatchers("/other/**").hasRole("USER")
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.httpBasic()
.and()
.authenticationProvider(authenticationProvider)
.csrf().disable();
}
@Bean
public CustomSecurityExpressionRoot customSecurityExpressionRoot(Authentication authentication) {
return new CustomSecurityExpressionRoot(authentication);
}
}
上面的代码保护"/admin"路径下的URL,只有管理员具有访问权限。而对于"/other"路径下的URL,则需要用户的角色为"USER"才能访问。
最后是两条示例:
示例1:检查用户是否为特定组织的管理员
public boolean hasOrganizationAdminPermission(String organizationId) {
Authentication authentication = getAuthentication();
if (authentication == null) {
return false;
}
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
Set<String> authorities = userDetails.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toSet());
String adminPrefix = "ORG_" + organizationId + "_ADMIN_";
// 如果 authorities 中有以 "ORG_组织ID_ADMIN_" 开头的权限,就说明当前用户是该组织的管理员
return authorities.stream().anyMatch(permission -> permission.startsWith(adminPrefix));
}
示例2: 检查用户是否属于某个角色(不仅检查角色名,还检查角色所属组织)
public boolean hasRoleWithOrganization(String roleWithOrganization) {
Authentication authentication = getAuthentication();
if (authentication == null) {
return false;
}
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
String[] splitted = roleWithOrganization.split("_");
if (splitted.length != 3) {
throw new IllegalArgumentException("roleWithOrganization argument should be in format ROLE_ORG_ROLENAME");
}
// Example: ROLE_ORG1_ADMIN -> {ROLE, ORG1, ADMIN}
String roleName = splitted[2];
String organization = splitted[1];
return userDetails.getAuthorities().stream()
.map(Object::toString)
.anyMatch(s -> s.equals(roleWithOrganization));
}
将这些方法添加到CustomSecurityExpressionRoot类中,同样使用"registerFunction()"方法将其注册到ExpressionParser中,如下所示:
public class CustomSecurityExpressionRoot extends SecurityExpressionRoot {
// 代码省略...
public CustomSecurityExpressionRoot(Authentication authentication) {
super(authentication);
}
// 注册自定义方法
public void registerFunctions(CustomSecurityExpressionParser parser) {
parser.registerFunction("hasPermission",
new HasPermissionMethod(this));
parser.registerFunction("hasOrganizationAdminPermission",
new HasOrganizationAdminPermissionMethod(this));
parser.registerFunction("hasRoleWithOrganization",
new HasRoleWithOrganizationMethod(this));
}
}
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解如何在Spring Security中自定义权限表达式 - Python技术站