北京高级网站建设seo快速推广
Spring Security 的权限控制是通过 SecurityContextHolder 中保存的认证信息(Authentication)进行的。权限信息来自 UserDetails 的 getAuthorities() 方法。
只要保证返回的 Collection<? extends GrantedAuthority> 包含 ROLE_xxx,就可以进行角色控制。
数据库设计
CREATE TABLE t_user (id INT PRIMARY KEY AUTO_INCREMENT,login_act VARCHAR(50),login_pwd VARCHAR(100),name VARCHAR(50),...
);CREATE TABLE t_role (id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(50), -- 角色名,例如 ADMIN、USERrole_key VARCHAR(50) -- 用于权限控制,例如 ROLE_ADMIN、ROLE_USER
);CREATE TABLE t_user_role (user_id INT,role_id INT,PRIMARY KEY (user_id, role_id)
);
对应实体类如下:
@Data
@TableName("t_user")
public class TUser {private Integer id;private String loginAct;private String loginPwd;private String name;// 不加 roles 字段到数据库映射,但需要接收它@TableField(exist = false)private List<TRole> roles;
}@Data
@TableName("t_role")
public class TRole {private Integer id;private String name;private String roleKey; // 例如 ROLE_ADMIN
}
Mapper
@Mapper
public interface TUserMapper extends BaseMapper<TUser> {TUser findByLoginAct(String loginAct);
}@Mapper
public interface TRoleMapper extends BaseMapper<TRole> {@Select("SELECT r.* FROM t_role r JOIN t_user_role ur ON r.id = ur.role_id WHERE ur.user_id = #{userId}")List<TRole> selectByUserId(@Param("userId") Integer userId);
}
LoginUser 实现 UserDetails
ok 封装这里在我上一篇博客说了,你想获得登录用户的信息就得去实现UserDetails接口,所以不多赘述了
public class LoginUser implements UserDetails {private final TUser user;public LoginUser(TUser user) {this.user = user;}@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {return user.getRoles().stream().map(role -> new SimpleGrantedAuthority(role.getRoleKey())).collect(Collectors.toList());}@Override public String getPassword() { return user.getLoginPwd(); }@Override public String getUsername() { return user.getLoginAct(); }@Override public boolean isAccountNonExpired() { return user.getAccountNoExpired() == 1; }@Override public boolean isAccountNonLocked() { return user.getAccountNoLocked() == 1; }@Override public boolean isCredentialsNonExpired() { return user.getCredentialsNoExpired() == 1; }@Override public boolean isEnabled() { return user.getAccountEnabled() == 1; }public TUser getUser() { return user; }
}
实现 UserDetailsService
依旧在我上一篇博客说了,Spring Security就是通过UserDetailService的loadUserByUsername方法来获取用户登录信息的,只不过这里我们相比于上一篇博客额外set了一下roles这个属性
@Service
public class UserDetailsServiceImpl implements UserDetailsService {@Autowired private TUserMapper userMapper;@Autowired private TRoleMapper roleMapper;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {TUser user = userMapper.findByLoginAct(username);if (user == null) throw new UsernameNotFoundException("用户不存在");List<TRole> roles = roleMapper.selectByUserId(user.getId());user.setRoles(roles);return new LoginUser(user);}
}
controller
你数据库中 role_key 是 ROLE_ADMIN,Spring Security 会自动把 hasRole(“ADMIN”) 转为 hasAuthority(“ROLE_ADMIN”) 匹配权限。所以你只需要:
数据库中角色字段保存如 ROLE_ADMIN
LoginUser 中返回 SimpleGrantedAuthority(“ROLE_ADMIN”)
就可以和controller层的注释 @PreAuthorize(“hasRole(‘ADMIN’)”)匹配上了
@RestController
public class UserController {@PreAuthorize("hasRole('ADMIN')")@GetMapping("/admin/dashboard")public String admin() {return "管理员页面";}@GetMapping("/me")public String me(@AuthenticationPrincipal LoginUser user) {return "当前用户:" + user.getUser().getName();}
}
安全配置类别SecurityConfig
别忘了配置这个类
@Configuration
@EnableMethodSecurity
public class SecurityConfig {@Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {return http.csrf(AbstractHttpConfigurer::disable).authorizeHttpRequests(auth -> auth.requestMatchers("/admin/**").hasRole("ADMIN").anyRequest().authenticated()).formLogin(Customizer.withDefaults()).build();}@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}
}