SpringBoot整合Spring Security(六)
一、OverView 在上一节中,使用了第一种方式:JDBC 连接数据库。这一节中将使用 Spring Data JPA 进行数据库操作。如果对 JPA 的环境和操作没了解过的,可以适当参考这个 。
在上一节也提到 Spring Security 支持多种数据源,这些不同来源的数据被共同封装成了一个 UserDetailService 接口
在这一节中,还是这个思路,这一次不用 Spring Security 提供的类, 可以自定义一个类去实现 UserDetailService
二、环境搭建 思路清晰,先看依赖
application.properties
1 2 3 4 5 6 7 8 9 spring.datasource.username =root spring.datasource.password =spring.datasource.url =jdbc:mysql://127.0.0.1:3306/security?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai spring.jpa.database =mysql spring.jpa.database-platform =mysql spring.jpa.hibernate.ddl-auto =update spring.jpa.show-sql =true spring.jpa.properties.hibernate.dialect =org.hibernate.dialect.MySQL8Dialect
实体类
User
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 @Entity(name = "t_user") public class User implements UserDetails { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String username; private String password; private boolean accountNonExpired; private boolean accountNonLocked; private boolean credentialsNonExpired; private boolean enabled; @ManyToMany(fetch = FetchType.EAGER,cascade = CascadeType.PERSIST) private List<Role> roles; @Override public Collection<? extends GrantedAuthority> getAuthorities() { List<SimpleGrantedAuthority> authorities = new ArrayList<>(); for (Role role : getRoles()) { authorities.add(new SimpleGrantedAuthority(role.getName())); } return authorities; } @Override public String getPassword () { return password; } @Override public String getUsername () { return username; } @Override public boolean isAccountNonExpired () { return accountNonExpired; } @Override public boolean isAccountNonLocked () { return accountNonLocked; } @Override public boolean isCredentialsNonExpired () { return credentialsNonExpired; } @Override public boolean isEnabled () { return enabled; } }
注:这里为什么 User 要实现 UserDetails ? 主要是由于在自定义类实现 UserDetailService,其中只有唯一的抽象方法loadUserByUsername,而该方法就是返回的 UserDetails
Role
1 2 3 4 5 6 7 8 @Entity(name = "t_role") public class Role { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; private String nameZh; }
UserDao
1 2 3 4 5 6 7 8 9 10 public interface UserDao extends JpaRepository <User , Long > { User findAllByUsername (String username) ; }
不懂为啥这么写的可以参考一下 JPA 的 CRUD 操作
UserService
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 @Service public class UserService implements UserDetailsService { private UserDao userDao; @Autowired public void setUserDao (UserDao userDao) { this .userDao = userDao; } @Override public UserDetails loadUserByUsername (String s) throws UsernameNotFoundException { User user = userDao.findAllByUsername(s); if (StringUtils.isEmpty(user)) { throw new UsernameNotFoundException("用户不存在" ); } return user; } User save (User user) { return userDao.save(user); } }
注:
实现了 UserDetailsService,重写其中的 loadUserByUsername 方法:通过传入的用户名查找用户信息
save 方法是为了后面写入不同角色用户
UserController
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @RestController public class UserController { private UserService userService; @Autowired public void setUserService (UserService userService) { this .userService = userService; } @PutMapping("/save") public User save (@RequestBody User user) { return userService.save(user); } }
将 SecurityConfig 中 configure 方法改为:
1 2 3 4 5 6 7 8 9 10 11 private UserService userService;@Autowired public void setUserService (UserService userService) { this .userService = userService; } @Override protected void configure (AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userService); }
三、Test Postman
由于在未登录的情况下,直接调用 localhost:8080/save 接口会失败,所以先在数据库中手动添加一个数据:
user 表:
role 表:
user_role 关系表:
使用上述增加的用户登录:
增加不同角色用户:
user 用户
admin用户
看下数据库:
user表
role表

user_role 关系表
此时在分别使用 user 用户和 admin 用户登录,看一下不同用户的权限:
user用户
user权限接口
admin权限接口