三、Spring Reactive Security从数据库查询用户
要从数据库查询用户,只需要配置数据库连接。同时实现的用户要实现org.springframework.security.core.userdetails.UserDetails
接口。从数据库查询用户要实现org.springframework.security.core.userdetails.ReactiveUserDetailsService
接口。
首先建表:
create table t_user(
id_key bigserial primary key,
username varchar(30),
password varchar(100),
Account_Non_Expired bool,
Account_Non_Locked bool,
Credentials_Non_Expired bool,
enabled bool
);
create table t_roles(
id_key bigserial primary key,
role_name varchar(20),
role_desc varchar(50)
);
create table t_user_roles(
id_key bigserial primary key,
user_id int8,
role_id int8
);
数据库选用Postgresql。t_user_roles是用户和角色关联表。
添加依赖:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
在application.properties
配置数据库连接:
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
spring.datasource.username=postgres
spring.datasource.password=xxxx
启动类配置mapper扫描路径:
@MapperScan("com.example.mapper")
添加用户实体类:
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Builder
@TableName("t_user")
public class UserEntity implements UserDetails {
/**
* 主键
*/
@TableId(type = IdType.AUTO)
private Long idKey;
/**
* 用户名
*/
private String username;
/**
* 密码
*/
private String password;
/**
* 账户是否过期
*/
private Boolean accountNonExpired;
/**
* 账户是否被锁定
*/
private Boolean accountNonLocked;
/**
* 密码是否过期
*/
private Boolean credentialsNonExpired ;
/**
* 是否启用
*/
private Boolean enabled;
@TableField(exist = false)
private Collection<SimpleGrantedAuthority> authorities;
public Long getIdKey() {
return idKey;
}
public void setIdKey(Long idKey) {
this.idKey = idKey;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
public void setAccountNonExpired(Boolean accountNonExpired) {
this.accountNonExpired = accountNonExpired;
}
public void setAccountNonLocked(Boolean accountNonLocked) {
this.accountNonLocked = accountNonLocked;
}
public void setCredentialsNonExpired(Boolean credentialsNonExpired) {
this.credentialsNonExpired = credentialsNonExpired;
}
public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}
public void setAuthorities(Collection<SimpleGrantedAuthority> authorities) {
this.authorities = authorities;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return null;
}
@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;
}
}
添加角色类:
@ToString
public class SimpleGrantedAuthority implements GrantedAuthority {
private String authority;
public SimpleGrantedAuthority(String authority) {
this.authority = authority;
}
@Override
public String getAuthority() {
return authority;
}
}
添加角色实体类:
@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
@TableName("t_roles")
public class RoleEntity {
/**
* 主键
*/
@TableId(type = IdType.AUTO)
private Long idKey;
/**
* 角色名
*/
private String roleName;
/**
* 角色描述
*/
private String roleDesc;
}
添加关联实体类:
@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
@TableName("t_user_roles")
public class UserRoleRelationEntity {
/**
* 主键
*/
@TableId(type = IdType.AUTO)
private Long idKey;
private Long userId;
private Long roleId;
}
添加mapper:
public interface RoleMapper extends BaseMapper<RoleEntity> {
}
public interface UserMapper extends BaseMapper<UserEntity> {
}
public interface UserRoleRelationMapper extends BaseMapper<UserRoleRelationEntity> {
}
添加密码加密器:
MyReactiveSecurityConfig.class
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
添加ReactiveUserDetailsService实现类:
@Service
@Slf4j
public class MyReactiveUserDetailsService implements ReactiveUserDetailsService {
@Autowired
private UserMapper userMapper;
@Autowired
private RoleMapper roleMapper;
@Autowired
private UserRoleRelationMapper userRoleRelationMapper;
@Override
public Mono<UserDetails> findByUsername(String username) {
log.info("用户名:{}从数据库查询用户", username);
UserEntity userEntity = userMapper.selectOne(Wrappers.lambdaQuery(UserEntity.class)
.eq(UserEntity::getUsername, username));
if (userEntity == null) {
log.info("用户名:{}从数据库未查询到用户", username);
return Mono.empty();
}
List<UserRoleRelationEntity> userRoleRelationEntities = userRoleRelationMapper.selectList(Wrappers.lambdaQuery(UserRoleRelationEntity.class)
.eq(UserRoleRelationEntity::getUserId, userEntity.getIdKey()));
log.info("用户名:{}从数据库查询角色:{}", username,userRoleRelationEntities);
if (!CollectionUtils.isEmpty(userRoleRelationEntities)) {
List<RoleEntity> roleEntities = roleMapper.selectList(Wrappers.lambdaQuery(RoleEntity.class)
.in(RoleEntity::getIdKey, userRoleRelationEntities.stream().map(UserRoleRelationEntity::getRoleId).collect(Collectors.toList())));
List<SimpleGrantedAuthority> roles = roleEntities.stream().map(RoleEntity::getRoleName).map(SimpleGrantedAuthority::new).collect(Collectors.toList());
userEntity.setAuthorities(roles);
log.info("用户名:{}从数据库查询到用户:{}", username,userEntity);
}
return Mono.just(userEntity);
}
}
添加新增用户测试:
@Autowired
private UserMapper userMapper;
@Autowired
private RoleMapper roleMapper;
@Autowired
private UserRoleRelationMapper userRoleRelationMapper;
@Autowired
private PasswordEncoder passwordEncoder;
@Test
public void test() {
addUser("USER","普通用户", "user","123");
addUser("ADMIN","管理员","admin","123");
}
private void addUser(String roleName,String roleDesc,String username,String password) {
RoleEntity role = RoleEntity.builder()
.roleDesc(roleDesc)
.roleName(roleName)
.build();
roleMapper.insert(role);
UserEntity user = UserEntity.builder().username(username)
.password(passwordEncoder.encode(password))
.accountNonExpired(true)
.accountNonLocked(true)
.enabled(true)
.credentialsNonExpired(true)
.build();
userMapper.insert(user);
UserRoleRelationEntity entity = UserRoleRelationEntity.builder()
.userId(user.getIdKey())
.roleId(role.getIdKey())
.build();
userRoleRelationMapper.insert(entity);
}