一、SpringSecurity - WebFlux
上篇文章我们讲解了SpringSecurity 整合JWT使用 Token 的方式认证授权,但是从前面的学习中应该可以发现,我们是在SpringMVC
环境下实现的,所写的过滤器都是基于Servlet
的。我们也知道Spring
很早就退出了WebFlux
异步非阻塞的web框架,是基于Netty
实现的一款高性能的web框架,性能要比SpringMVC
高的多,还有现在我们常用的SpringGateWay
网关也是基于WebFlux
框架实现的,而在WebFlux
环境下的认证授权就和前面基于SpringMVC
的方式不太一样了,整体来说相差不大,但有些地方实现起来还是有差异,所以本篇文章我们一起学习下WebFlux
环境下的用户动态认证,在后面的文章我会继续讲解WebFlux
环境下的动态角色权限,及整合JWT
使用Token
的方式认证授权。
在学习本篇文章最好已经了解了SpringSecurity
,不了解的可以看下本专栏的其他讲解SpringSecurity
的博客,下面是上篇文章的地址:
二、环境搭建准备
新建一个SpringBoot项目,在pom中引入以下依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
下面新建两个测试接口,后面就使用这个接口做测试:
@RestController
public class TestController {
@GetMapping("/admin/test")
public Mono<String> adminTest(){
return Mono.just("success : /admin/test ");
}
@GetMapping("/common/test")
public Mono<String> commonTest(){
return Mono.just("success : /common/test ");
}
}
启动项目,在浏览器请求我们的接口:http://localhost:8080/admin/test
看到这个页面,我们应该就熟悉了,和前面讲用户认证的时候也是出现这个页面,这里的密码也是打印在了控制台中:
用户名默认user
,输入上面控制台打印的密码,就可以访问接口了:
这里的用户名密码还是和前面讲的一样,我们可以配制在配制文件中也可以,在使用程序配制的方式配制,比如可以加上下面这个配制类。
@Configuration
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
public class SecurityConfig {
@Bean
public ReactiveUserDetailsService userDetailsService() {
UserDetails user = User.withUsername("admin").password(passwordEncoder().encode("1234")).authorities("admin").build();
return new MapReactiveUserDetailsService(user);
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
再次启动项目,就可以使用admin
用户来登录了:
显然使用上面这些用户认证方式,都达不到我们想要的效果,在前面的文章中我们都是基于数据库的认证,同样在WebFlux
中也要使用数据库,下面我们就看下使用数据库的方式认证。
三、数据库的方式认证
在这里我们还是使用在前几篇文章中创建的表,包括实体类,这里就不把代码给复制进来了。
在前面做数据库认证的时候我们是创建一个UserService
并实现了UserDetails
接口,在Webflux
中就不是UserDetails
,现在要换成ReactiveUserDetailsService
接口了,整个接口中只有一个抽象方法findByUsername
,其中传入的参数还是和前面的一致,是用户名,我们可以根据用户名查询到用户的信息及角色或权限,返回出去,对于返回是一个Mono
但其中的类型还是和前面的一致,都是UserDetails
对象。
下面我们写一个UserDetailService
来实现ReactiveUserDetailsService
接口:
@Service
public class UserDetailService implements ReactiveUserDetailsService {
@Autowired
UserMapper userMapper;
@Autowired
RoleMapper roleMapper;
@Override
public Mono<UserDetails> findByUsername(String username) {
return Mono.fromCallable(()->{
LambdaQueryWrapper<UserEntity> wrapper = new LambdaQueryWrapper<UserEntity>()
.eq(UserEntity::getUsername, username);
UserEntity userEntity = userMapper.selectOne(wrapper);
if (userEntity == null) {
throw new UsernameNotFoundException("用户不存在!");
}
List<GrantedAuthority> auths = roleMapper.getAllRoleByUserId(userEntity.getId())
.stream()
.map(r -> new SimpleGrantedAuthority(r.getRole()))
.collect(Collectors.toList());
userEntity.setRoles(auths);
return userEntity;
});
}
}
其中的逻辑和前面的完全一致,下面修改SecurityConfig
配制:
@Configuration
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
public class SecurityConfig {
@Autowired
UserDetailService userDetailService;
@Bean
public ReactiveAuthenticationManager authenticationManager() {
UserDetailsRepositoryReactiveAuthenticationManager authenticationManager = new UserDetailsRepositoryReactiveAuthenticationManager(userDetailService);
authenticationManager.setPasswordEncoder(passwordEncoder());
return authenticationManager;
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
再次启动项目,就可以使用数据库中的用户认证了:
喜欢的小伙伴可以关注我的个人微信公众号,获取更多学习资料!