Spring Boot 实现权限管理
Spring Boot 实现权限管理大致有2种方式,一种比较常规且简单的Spring Boot + Spring Security + MyBatis,另一种Spring Boot + Spring Security + JWT。
我们先要明白权限管理的本质,就是一系列挡在控制器前面的过滤器,实现权限管理,也就是设置并实现过滤器的过程。
方案1:Spring Boot + Spring Security + MyBatis
(1)你的数据库要先有sys_user、sys_role和sys_user_role这些表来表示用户和权限的链接。
(2)实现 UserDetailsService
:
UserDetailsService
是 Spring Security 框架里的一个核心接口。其作用是从存储(如数据库、LDAP 等)中加载用户信息,为认证和授权流程提供必要的用户数据。
java
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 1. 查询用户(以手机号登录为例)
SysUser user = userMapper.findByPhoneNumber(phoneNumber)
.orElseThrow(() -> new UsernameNotFoundException("用户不存在"));
// 2. 查询用户的角色和权限
List<GrantedAuthority> authorities = new ArrayList<>();
//GrantedAuthority 是 Spring Security 框架里的一个接口,它代表了用户所拥有的权限或者角色。在 Spring Security 的认证和授权体系中,GrantedAuthority 扮演着关键角色,主要用于描述用户被授予的权限信息。
// 2 添加角色
user.getRoles().forEach(role -> {
authorities.add(new SimpleGrantedAuthority(role.getName()));
});
// 3. 返回 Spring Security 的 User 对象
return new org.springframework.security.core.userdetails.User(
user.getUsername(),
user.getPassword(),
authorities
);
}
}
UserDetails 是 Spring Security 框架里的一个核心接口,其主要作用是封装用户的核心信息,这些信息会在认证和授权过程中被使用。Spring Security 在进行用户认证和权限检查时,需要依据 UserDetails 对象里的信息来判断用户是否具备相应的权限。
java
package org.springframework.security.core.userdetails;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import java.io.Serializable;
import java.util.Collection;
public interface UserDetails extends Serializable {
// 获取用户的权限集合
Collection<? extends GrantedAuthority> getAuthorities();
// 获取用户的密码
String getPassword();
// 获取用户名
String getUsername();
// 判断用户账户是否未过期
boolean isAccountNonExpired();
// 判断用户账户是否未被锁定
boolean isAccountNonLocked();
// 判断用户的凭证(如密码)是否未过期
boolean isCredentialsNonExpired();
// 判断用户账户是否启用
boolean isEnabled();
}
(3)配置 Spring Security
在用户登录以后刚刚写的CustomUserDetailsService 是隐式调用的,完全由Spring Boot管理和调用,后续只需要配置SecurityConfig,SecurityConfig便会根据CustomUserDetailsService返回的结果进行拦截,即权限控制。
java
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/login", "/public/**").permitAll() // 公开接口
.requestMatchers("/user/**").hasAuthority("user") // 需具体权限
.anyRequest().authenticated() // 其他接口需登录
)
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(); // 密码加密
}
}
现在就可以在整个Spring Boot项目中实现权限管理了。
权限控制方式
scss
permitAll():无条件允许任何形式访问,不管你登录还是没有登录。
anonymous():允许匿名访问,也就是没有登录才可以访问。
denyAll():无条件决绝任何形式的访问。
authenticated():只允许已认证的用户访问。
fullyAuthenticated():只允许已经登录或者通过 remember-me 登录的用户访问。
hasRole(String) : 只允许指定的角色访问。
hasAnyRole(String) : 指定一个或者多个角色,满足其一的用户即可访问。
hasAuthority(String):只允许具有指定权限的用户访问hasAnyAuthority(String):指定一个或者多个权限,满足其一的用户即可访问。
hasIpAddress(String) : 只允许指定 ip 的用户访问。
(1)URL 级别权限:
在 SecurityConfig 中配置:
java
.requestMatchers("/admin/**").hasRole("ADMIN")
.requestMatchers("/user/**").hasAuthority("user")
(2)方法级别权限
使用 @PreAuthorize 注解:
java
@RestController
@RequestMapping("/api/user")
public class UserController {
// 需 ADMIN 角色或 user 权限
@PreAuthorize("hasRole('ADMIN') or hasAuthority('user')")
@DeleteMapping("/{id}")
public String deleteUser(@PathVariable Long id) {
return "删除用户成功";
}
// 需 user 权限
@PreAuthorize("hasAuthority('user')")
@GetMapping("/{id}")
public String getUser(@PathVariable Long id) {
return "用户信息";
}
}
注意 :需在配置类上添加@EnableGlobalMethodSecurity
:
java
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig {
}
这种方法对性能不友好,因为每一次请求都会触发过滤器去调动mapper层方法,对数据库进行访问,一旦请求量大了,数据库的压力也大。
另一种方案在下篇介绍。