SpringBoot整合Spring Security,使用数据库鉴权(四)

╰半夏微凉° 2022-12-10 01:12 270阅读 0赞

一、实现UserDetails接口

  1. package com.example.securityzimug.config.auth;
  2. import org.springframework.security.core.GrantedAuthority;
  3. import org.springframework.security.core.userdetails.UserDetails;
  4. import java.util.Collection;
  5. public class MyUserDetails implements UserDetails {
  6. String password; //密码
  7. String username; //用户名
  8. boolean accountNonExpired; //是否没过期
  9. boolean accountNonLocked; //是否没被锁定
  10. boolean credentialsNonExpired; //是否没过期
  11. boolean enabled; //账号是否可用
  12. Collection<? extends GrantedAuthority> authorities; //用户的权限集合
  13. @Override
  14. public Collection<? extends GrantedAuthority> getAuthorities() {
  15. return authorities;
  16. }
  17. @Override
  18. public String getPassword() {
  19. return password;
  20. }
  21. @Override
  22. public String getUsername() {
  23. return username;
  24. }
  25. @Override
  26. public boolean isAccountNonExpired() {
  27. return true;
  28. }
  29. @Override
  30. public boolean isAccountNonLocked() {
  31. return true;
  32. }
  33. @Override
  34. public boolean isCredentialsNonExpired() {
  35. return true;
  36. }
  37. @Override
  38. public boolean isEnabled() {
  39. return enabled;
  40. }
  41. public void setPassword(String password) {
  42. this.password = password;
  43. }
  44. public void setUsername(String username) {
  45. this.username = username;
  46. }
  47. public void setAccountNonExpired(boolean accountNonExpired) {
  48. this.accountNonExpired = accountNonExpired;
  49. }
  50. public void setAccountNonLocked(boolean accountNonLocked) {
  51. this.accountNonLocked = accountNonLocked;
  52. }
  53. public void setCredentialsNonExpired(boolean credentialsNonExpired) {
  54. this.credentialsNonExpired = credentialsNonExpired;
  55. }
  56. public void setEnabled(boolean enabled) {
  57. this.enabled = enabled;
  58. }
  59. public void setAuthorities(Collection<? extends GrantedAuthority> authorities) {
  60. this.authorities = authorities;
  61. }
  62. }

二、编写mapper

在编写之前需要导入依赖。

  1. <dependency>
  2. <groupId>org.mybatis.spring.boot</groupId>
  3. <artifactId>mybatis-spring-boot-starter</artifactId>
  4. <version>2.1.3</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>mysql</groupId>
  8. <artifactId>mysql-connector-java</artifactId>
  9. </dependency>
  10. package com.example.securityzimug.config.auth;
  11. import org.apache.ibatis.annotations.Mapper;
  12. import org.apache.ibatis.annotations.Param;
  13. import org.apache.ibatis.annotations.Select;
  14. import java.util.List;
  15. @Mapper
  16. public interface MyUserDetailsServiceMapper {
  17. //根据userID查询用户信息
  18. @Select("SELECT username,password,enabled\n" +
  19. "FROM sys_user u\n" +
  20. "WHERE u.username = #{userId} or u.phone = #{userId}")
  21. MyUserDetails findByUserName(@Param("userId") String userId);
  22. //根据userID查询用户角色列表
  23. @Select("SELECT role_code\n" +
  24. "FROM sys_role r\n" +
  25. "LEFT JOIN sys_user_role ur ON r.id = ur.role_id\n" +
  26. "LEFT JOIN sys_user u ON u.id = ur.user_id\n" +
  27. "WHERE u.username = #{userId} or u.phone = #{userId}")
  28. List<String> findRoleByUserName(@Param("userId") String userId);
  29. //根据用户角色查询用户权限
  30. @Select({
  31. "<script>",
  32. "SELECT url " ,
  33. "FROM sys_menu m " ,
  34. "LEFT JOIN sys_role_menu rm ON m.id = rm.menu_id " ,
  35. "LEFT JOIN sys_role r ON r.id = rm.role_id ",
  36. "WHERE r.role_code IN ",
  37. "<foreach collection='roleCodes' item='roleCode' open='(' separator=',' close=')'>",
  38. "#{roleCode}",
  39. "</foreach>",
  40. "</script>"
  41. })
  42. List<String> findAuthorityByRoleCodes(@Param("roleCodes") List<String> roleCodes);
  43. }

三、实现UserDetailsService接口

  1. package com.example.securityzimug.config.auth;
  2. import org.springframework.security.core.authority.AuthorityUtils;
  3. import org.springframework.security.core.userdetails.UserDetails;
  4. import org.springframework.security.core.userdetails.UserDetailsService;
  5. import org.springframework.security.core.userdetails.UsernameNotFoundException;
  6. import org.springframework.stereotype.Component;
  7. import javax.annotation.Resource;
  8. import java.util.List;
  9. import java.util.stream.Collectors;
  10. /**
  11. * @author baikunlong
  12. * @date 2020/9/22 23:14
  13. */
  14. @Component
  15. public class MyUserDetailsService implements UserDetailsService {
  16. @Resource
  17. private MyUserDetailsServiceMapper myUserDetailsServiceMapper;
  18. @Override
  19. public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
  20. MyUserDetails myUserDetails = myUserDetailsServiceMapper.findByUserName(username);
  21. //角色集合
  22. List<String> roleList = myUserDetailsServiceMapper.findRoleByUserName(username);
  23. //资源权限集合
  24. List<String> authorities = myUserDetailsServiceMapper.findAuthorityByRoleCodes(roleList);
  25. //角色是特殊的权限,前缀规定为ROLE_
  26. roleList=roleList.stream().map(role->"ROLE_"+role).collect(Collectors.toList());
  27. authorities.addAll(roleList);
  28. myUserDetails.setAuthorities(AuthorityUtils.commaSeparatedStringToAuthorityList(String.join(",",authorities)));
  29. return myUserDetails;
  30. }
  31. }

四、修改配置类

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2JhaWt1bmxvbmc_size_16_color_FFFFFF_t_70

注意这里的UserDetailsService一定要使用注入方式,我一开始手动new的,这会导致mapper为空,在service那排错了很久,后来才发现是这边的问题。

20200923090551627.png

五、修改配置文件

  1. spring:
  2. security:
  3. # 用数据库后,内存模式的就先注释掉吧
  4. # user:
  5. # name: admin
  6. # password: admin
  7. loginType: JSON
  8. datasource:
  9. url: jdbc:mysql://localhost:3306/study_springboot_05_security_zimug?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
  10. username: root
  11. password: '123456'
  12. driver-class-name: com.mysql.cj.jdbc.Driver
  13. #logging:
  14. # level:
  15. # root: debug

需要注意的是,配置文件如果是yml文件类型的,密码一定要加单引号或者双引号,不然连接不了数据库的,properties不存在这个问题。

六、动态鉴权

在一开始我们的鉴权都是写的静态的,当有新需求时可能会更改代码,所以需要动态的鉴权。

编写一个类来鉴权。

  1. package com.example.securityzimug.config.auth;
  2. import org.springframework.security.core.Authentication;
  3. import org.springframework.security.core.GrantedAuthority;
  4. import org.springframework.security.core.authority.AuthorityUtils;
  5. import org.springframework.security.core.userdetails.UserDetails;
  6. import org.springframework.stereotype.Component;
  7. import javax.servlet.http.HttpServletRequest;
  8. import java.util.List;
  9. @Component("rabcService")
  10. public class MyRBACService {
  11. /**
  12. * 判断某用户是否具有该request资源的访问权限
  13. */
  14. public boolean hasPermission(HttpServletRequest request, Authentication authentication){
  15. //这个就是UserDetails
  16. Object principal = authentication.getPrincipal();
  17. if(principal instanceof UserDetails){
  18. UserDetails userDetails = ((UserDetails)principal);
  19. //这里的请求地址就是资源权限名
  20. List<GrantedAuthority> authorityList =
  21. AuthorityUtils.commaSeparatedStringToAuthorityList(request.getRequestURI());
  22. //判断当前用户是否有这个资源权限
  23. return userDetails.getAuthorities().contains(authorityList.get(0));
  24. }
  25. return false;
  26. }
  27. }

然后在配置类里更改下权限配置:

20200923100745395.png

发表评论

表情:
评论列表 (有 0 条评论,270人围观)

还没有评论,来说两句吧...

相关阅读