除了之前介绍的内置基础权限控制外。Spring Security 中还支持很多其他权限控制。这些方法一般都用于用户已经被认证成功后(登录成功后),判断用户是否具有特定的权限,如角色、菜单权限等。
判断用户是否具有特定的权限,用户的权限是在自定义登录逻辑中创建User对象时指定的。例如:
package com.hxstrive.spring_security.config; import com.hxstrive.spring_security.service.UserService; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import java.util.List; /** * 自定义实现 UserDetailsService 接口 * @author hxstrive.com */ public class CustomUserDetailsService implements UserDetailsService { // 用户服务 private final UserService userService; public CustomUserDetailsService(UserService userService) { this.userService = userService; } @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { System.out.println("loadUserByUsername(String username) :: " + username); // 从数据库中加载用户信息 com.hxstrive.spring_security.model.UserModel user = userService.getByCount(username); if(null == user){ // 用户名不存在。抛出异常 throw new UsernameNotFoundException("用户名 [" + username + "] 不存在"); } // 【看这里】 // 获取用户权限信息,返回一个字符串集合 List<String> authorities = userService.getUserAuthorities(user.getId()); // 创建 UserDetails 对象 return new User(username, user.getPassword(), AuthorityUtils.createAuthorityList(authorities)); } }
上述 userService.getUserAuthorities(user.getId()) 代码将根据用户 ID 到数据库获取用户拥有的所有角色和菜单权限。
注意,角色需要在角色名称前面添加“ROLE_”前缀。
示例:
http.authorizeHttpRequests(authorize -> authorize // 需要具有 menu:sys:add 权限才能访问 /sys/add 路径的请求 .requestMatchers("/sys/add").hasAuthority("menu:sys:add") // 需要具有 role_admin 角色才能访问 /sys 路径的请求 // hasAuthority() 也可以使用 hasRole(),二者是等价的 .requestMatchers("/sys/**").hasAuthority("role_admin") .anyRequest().authenticated() // 其他请求需认证 )
上述代码,配置访问 /sys 开头的路径,需要 “admin”角色权限,访问 /sys/add 需要“menu:sys:add”权限。
用于检查用户是否拥有任意一个指定的权限。它允许你定义多个权限选项,只要用户拥有其中之一即可访问资源。
示例:
http.authorizeHttpRequests(authorize -> authorize // 需要具有 menu:sys:add 或 role_admin 权限才能访问 /sys/add 路径的请求 .requestMatchers("/sys/add").hasAnyAuthority("menu:sys:add", "role_admin") .anyRequest().authenticated() // 其他请求需认证 )
如果用户具备给定角色就允许访问,否则出现 403。
参数取值来源于自定义登录逻辑 UserDetailsService 实现类中创建 User 对象时给 User 赋予的授权。
在给用户赋予角色时角色需要以:ROLE_ 开头,后面添加角色名称。例如:ROLE_admin 其中 admin 是角色名,ROLE_ 是固定的字符开头。使用 hasRole() 时参数也只写 admin 即可。
给用户赋予角色:
@Override public List<String> getUserAuthorities(int userId) { final List<String> retList = new ArrayList<>(); // 用户拥有的角色 List<RoleModel> roleModelList = roleService.getUserAllRole(userId); roleModelList.forEach(roleModel -> retList.add("ROLE_" + roleModel.getCode())); // 用户拥有的菜单 List<MenuModel> menuCodeList = menuService.getUserAllMenu(userId); menuCodeList.forEach(menuModel -> retList.add(menuModel.getPermission())); return retList; }
示例:
http.authorizeHttpRequests(authorize -> authorize // 需要具有 admin 角色权限才能访问 /sys 路径的请求 .requestMatchers("/sys/**").hasRole("admin") .anyRequest().authenticated() // 其他请求需认证 )
用于判断用户是否拥有任意一个指定角色。与 hasAnyAuthority 相比,它会自动为角色名添加 ROLE_ 前缀,使权限配置更简洁。
示例:
http.authorizeHttpRequests(authorize -> authorize // 需要具有 admin 或 normal 角色权限才能访问 /user 路径的请求 .requestMatchers("/user/**").hasAnyRole("admin", "normal") // 需要具有 admin 角色权限才能访问 /sys 路径的请求 .requestMatchers("/sys/**").hasRole("admin") .anyRequest().authenticated() // 其他请求需认证 )
注意,上面介绍的四个权限或角色判断方法其底层实际上使用的是 access() 方法,如下图:
我们将在下一章节详细介绍 access() 方法的使用。