关于 SpringDataJpa 的学习可以参考:学习 Spring Data JPA 一篇文章就够了
一、创建工程
注意,除了 Spring Security 依赖之外,我们还需要数据依赖和 Spring Data Jpa 依赖。
工程创建完成后,我们再在数据库中创建一个空的库,就叫做 jpa,里边什么都不用做,这样我们的准备工作就算完成了。
二、准备模型
(1)角色实体类:
@Entity(name = "t_role")
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String nameZh;
//省略 getter/setter
}
这个实体类用来描述用户角色信息,有角色 id、角色名称(英文、中文),@Entity
表示这是一个实体类,项目启动后,将会根据实体类的属性在数据库中自动创建一个角色表。
(2)用户实体类
@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;
}
//省略其他 get/set 方法
}
用户实体类主要需要实现 UserDetails
接口,并实现接口中的方法。
这里的字段基本都好理解,几个特殊的我来稍微说一下:
(1)
accountNonExpired
、accountNonLocked
、credentialsNonExpired
、enabled
这四个属性分别用来描述用户的状态,表示账户是否没有过期、账户是否没有被锁定、密码是否没有过期、以及账户是否可用。
(2)roles 属性表示用户的角色,User 和 Role 是多对多关系,用一个@ManyToMany
注解来描述。
(3)getAuthorities 方法返回用户的角色信息,我们在这个方法中把自己的 Role 稍微转化一下即可。
三、配置
数据模型准备好之后,我们再来定义一个 UserDao:
public interface UserDao extends JpaRepository<User,Long> {
User findUserByUsername(String username);
}
这里的东西很简单,我们只需要继承 JpaRepository
然后提供一个根据 username 查询 user 的方法即可。
在接下来定义 UserService ,如下:
@Service
public class UserService implements UserDetailsService {
@Autowired
UserDao userDao;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userDao.findUserByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("用户不存在");
}
return user;
}
}
Наше собственное определение UserService
необходимости создания UserDetailsService
интерфейса, этого интерфейса, методов интерфейса, которые должны достичь, то есть loadUserByUsername
после параметра этого метода является то, что когда пользователи регистрируют входящее имя пользователя, имя пользователя для запроса информации о пользователе (проверьте , Система автоматически сравнит пароли).
После завершения настройки давайте сделаем небольшую настройку в Spring Security. Я все еще использую Spring Security и HelloController, которые использовались для тестирования из предыдущей статьи, в основном перечисляя места, которые необходимо изменить.
В SecurityConfig мы настраиваем пользователей следующими способами:
@Autowired
UserService userService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService);
}
Обратите внимание, что мы все еще переписываем метод настройки, но на этот раз мы не на основе памяти и не на ее основе JdbcUserDetailsManager
, а используем собственный UserService
, поэтому с конфигурацией все в порядке.
Наконец, мы настраиваем основную информацию о базе данных и JPA в application.properties следующим образом:
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.url=jdbc:mysql://localhost:3306/jpa?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
Четыре, тест
Сначала добавим тестовые данные, добавим в модульный тест следующий метод:
@Test
void contextLoads() {
User user = new User();
user.setUsername("yolo");
user.setPassword("123");
user.setAccountNonExpired(true);
user.setAccountNonLocked(true);
user.setCredentialsNonExpired(true);
user.setEnabled(true);
List<Role> list = new ArrayList<>();
Role role = new Role();
role.setName("ROLE_admin");
role.setNameZh("管理员");
list.add(role);
user.setRoles(list);
userDao.save(user);
}
После успешного входа в систему , доступа соответственно /hello,/admin/hello
и /user/hello
три интерфейса, в том числе:
(1)
/hello
Поскольку вы можете получить доступ после входа в систему, этот интерфейс успешно доступен.
(2)/admin/hello
Требуется учетная запись администратора, поэтому доступ не выполняется.
(3)/user/hello
Требуется идентификатор пользователя, поэтому доступ успешен.