一篇文章带你搞定 SpringSecurity 和 SpringDataJpa 的整合

关于 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) accountNonExpiredaccountNonLockedcredentialsNonExpiredenabled 这四个属性分别用来描述用户的状态,表示账户是否没有过期、账户是否没有被锁定、密码是否没有过期、以及账户是否可用。
(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Требуется идентификатор пользователя, поэтому доступ успешен.

рекомендация

отblog.csdn.net/nanhuaibeian/article/details/108607430