SpringSecurity5(14-Gateway整合)
MVC 与 WebFlux 关系
SpringSecurity 设置要采用响应式配置,基于 WebFlux 中 WebFilter 实现,与 Spring MVC 的 Security 是通过 Servlet 的 Filter 实现类似,也是一系列 filter 组成的过滤链。
Reactor 与传统 MVC 配置对应:
webflux | mvc | 作用 |
---|---|---|
@EnableWebFluxSecurity | @EnableWebSecurity | 开启 security 配置 |
ServerAuthenticationSuccessHandler | AuthenticationSuccessHandler | 登录成功 Handler |
ServerAuthenticationFailureHandler | AuthenticationFailureHandler | 登录失败 Handler |
ServerLogoutSuccessHandler | LogoutSuccessHandler | 注销成功Handler |
ServerSecurityContextRepository | SecurityContextHolder | 认证信息存储管理 |
ReactiveUserDetailsService | UserDetailsService | 用户登录逻辑处理 |
ReactiveAuthenticationManager | AuthorizationManager | 认证管理 |
ReactiveAuthorizationManager | AccessDecisionManager | 鉴权管理 |
ServerAuthenticationEntryPoint | AuthenticationEntryPoint | 未认证 Handler |
ServerAccessDeniedHandler | AccessDeniedHandler | 鉴权失败 Handler |
AuthenticationWebFilter | FilterSecurityInterceptor | 拦截器 |
快速入门
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.38</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
内存管理用户信息
@EnableWebFluxSecurity
@Configuration
public class SecurityConfig {
@Bean
public SecurityWebFilterChain filterChain(ServerHttpSecurity http) {
http.httpBasic()
.and()
.authorizeExchange()
.anyExchange()
.authenticated();
return http.build();
}
/**
* 内存管理用户信息
*/
@Bean
public MapReactiveUserDetailsService userDetailsService() {
UserDetails user = User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build();
return new MapReactiveUserDetailsService(user);
}
}
自定义登录、注销处理器
- 自定义登录成功处理器
@Component
public class LoginSuccessHandler implements ServerAuthenticationSuccessHandler {
@Override
public Mono<Void> onAuthenticationSuccess(WebFilterExchange webFilterExchange, Authentication authentication) {
return Mono.defer(() -> Mono.just(webFilterExchange.getExchange().getResponse()).flatMap(response -> {
DataBufferFactory dataBufferFactory = response.bufferFactory();
DataBuffer dataBuffer = dataBufferFactory.wrap("登录成功".getBytes());
return response.writeWith(Mono.just(dataBuffer));
}));
}
}
- 自定义登录失败处理器
@Component
public class LoginFailHandler implements ServerAuthenticationFailureHandler {
@Override
public Mono<Void> onAuthenticationFailure(WebFilterExchange webFilterExchange, AuthenticationException exception) {
return Mono.defer(() -> Mono.just(webFilterExchange.getExchange().getResponse()).flatMap(response -> {
DataBufferFactory dataBufferFactory = response.bufferFactory();
DataBuffer dataBuffer = dataBufferFactory.wrap("登录失败".getBytes());
return response.writeWith(Mono.just(dataBuffer));
}));
}
}
- 自定义注销成功处理器
@Component
public class LogoutSuccessHandler implements ServerLogoutSuccessHandler {
@Override
public Mono<Void> onLogoutSuccess(WebFilterExchange exchange, Authentication authentication) {
return Mono.defer(() -> Mono.just(exchange.getExchange().getResponse()).flatMap(response -> {
DataBufferFactory dataBufferFactory = response.bufferFactory();
DataBuffer dataBuffer = dataBufferFactory.wrap("logout success".getBytes());
return response.writeWith(Mono.just(dataBuffer));
}));
}
}
@EnableWebFluxSecurity
@Configuration
public class SecurityConfig {
@Resource
private LoginSuccessHandler loginSuccessHandler;
@Resource
private LoginFailHandler loginFailHandler;
@Resource
private LogoutSuccessHandler logoutSuccessHandler;
@Bean
public SecurityWebFilterChain filterChain(ServerHttpSecurity http) {
http.httpBasic()
.and()
.authorizeExchange()
.anyExchange()
.authenticated();
http.formLogin()
.authenticationSuccessHandler(loginSuccessHandler)
.authenticationFailureHandler(loginFailHandler)
.and()
.logout()
.logoutSuccessHandler(logoutSuccessHandler);
return http.build();
}
/**
* 内存管理用户信息
*/
@Bean
public MapReactiveUserDetailsService userDetailsService() {
UserDetails user = User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build();
return new MapReactiveUserDetailsService(user);
}
}
自定义用户信息
- 仿照 MapReactiveUserDetailsService 编写获取用户认证类
@Component
public class UserDetailService implements ReactiveUserDetailsService, ReactiveUserDetailsPasswordService {
private final Map<String, UserDetails> users = new HashMap<>();
@Resource
private PasswordEncoder passwordEncoder;
@Override
public Mono<UserDetails> findByUsername(String username) {
User user = null;
if ("user".equals(username)) {
user = new User("user", passwordEncoder.encode("123456"), true, true, true, true, new ArrayList<>());
}
return Mono.justOrEmpty(user);
}
@Override
public Mono<UserDetails> updatePassword(UserDetails user, String newPassword) {
return Mono.just(user)
.map(u ->
User.withUserDetails(u)
.password(newPassword)
.build()
)
.doOnNext(u -> {
this.users.put(user.getUsername().toLowerCase(), u);
});
}
}
- 仿照 AbstractUserDetailsReactiveAuthenticationManager 编写用户认证管理类
@Component
public class UserAuthenticationManager extends AbstractUserDetailsReactiveAuthenticationManager {
@Resource
private PasswordEncoder passwordEncoder;
@Resource
private ReactiveUserDetailsService userDetailService;
@Resource
private ReactiveUserDetailsPasswordService userDetailsPswService;
private Scheduler scheduler = Schedulers.boundedElastic();
private UserDetailsChecker preAuthenticationChecks = user -> {
if (!user.isAccountNonLocked()) {
logger.debug("User account is locked");
throw new LockedException(this.messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.locked",
"User account is locked"));
}
if (!user.isEnabled()) {
logger.debug("User account is disabled");
throw new DisabledException(this.messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.disabled",
"User is disabled"));
}
if (!user.isAccountNonExpired()) {
logger.debug("User account is expired");
throw new AccountExpiredException(this.messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.expired",
"User account has expired"));
}
};
private UserDetailsChecker postAuthenticationChecks = user -> {
if (!user.isCredentialsNonExpired()) {
logger.debug("User account credentials have expired");
throw new CredentialsExpiredException(this.messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.credentialsExpired",
"User credentials have expired"));
}
};
@Override
public Mono<Authentication> authenticate(Authentication authentication) {
final String username = authentication.getName();
final String presentedPassword = (String) authentication.getCredentials();
return retrieveUser(username)
.doOnNext(this.preAuthenticationChecks::check)
.publishOn(this.scheduler)
.filter(u -> this.passwordEncoder.matches(presentedPassword, u.getPassword()))
.switchIfEmpty(Mono.defer(() -> Mono.error(new BadCredentialsException("Invalid Credentials"))))
.flatMap(u -> {
boolean upgradeEncoding = this.userDetailsPswService != null
&& this.passwordEncoder.upgradeEncoding(u.getPassword());
if (upgradeEncoding) {
String newPassword = this.passwordEncoder.encode(presentedPassword);
return this.userDetailsPswService.updatePassword(u, newPassword);
}
return Mono.just(u);
})
.doOnNext(this.postAuthenticationChecks::check)
.map(u -> new UsernamePasswordAuthenticationToken(u, u.getPassword(), u.getAuthorities()) );
}
@Override
protected Mono<UserDetails> retrieveUser(String username) {
return userDetailService.findBysername(username);
}
}
@EnableWebFluxSecurity
@Configuration
public class SecurityConfig {
@Resource
private LoginSuccessHandler loginSuccessHandler;
@Resource
private LoginFailHandler loginFailHandler;
@Resource
private LogoutSuccessHandler logoutSuccessHandler;
@Resource
private UserAuthenticationManager userAuthenticationManager;
@Bean
public SecurityWebFilterChain filterChain(ServerHttpSecurity http) {
http.httpBasic()
.and()
.authorizeExchange()
.anyExchange()
.authenticated();
http.formLogin()
.authenticationManager(authenticationManager())
.authenticationSuccessHandler(loginSuccessHandler)
.authenticationFailureHandler(loginFailHandler)
.and()
.logout()
.logoutSuccessHandler(logoutSuccessHandler);
return http.build();
}
/**
* 注册用户信息验证管理器,可按需求添加多个按顺序执行
*/
@Bean
public ReactiveAuthenticationManager authenticationManager() {
LinkedList<ReactiveAuthenticationManager> managers = new LinkedList<>();
managers.add(userAuthenticationManager);
return new DelegatingReactiveAuthenticationManager(managers);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
权限注解
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
@Configuration
public class SecurityConfig {
// ....
}
@RestController
public class TestController {
/**
* 无效
*/
@Secured({"ROLE_ADMIN"})
@RequestMapping(value = "/test")
public Mono<String> test() {
return Mono.just("test");
}
/**
* 有效
*/
@PreAuthorize("hasRole('ADMIN')")
@RequestMapping(value = "/test1")
public Mono<String> test1() {
return Mono.just("test1");
}
@Secured({"ROLE_TEST"})
@RequestMapping(value = "/test2")
public Mono<String> test2() {
return Mono.just("test2");
}
}
自定义权限处理器
@Component
public class AccessDeniedHandler implements ServerAccessDeniedHandler {
@Override
public Mono<Void> handle(ServerWebExchange exchange, AccessDeniedException denied) {
return Mono.defer(() -> Mono.just(exchange.getResponse()).flatMap(response -> {
DataBufferFactory dataBufferFactory = response.bufferFactory();
DataBuffer dataBuffer = dataBufferFactory.wrap("permission denied".getBytes());
return response.writeWith(Mono.just(dataBuffer));
}));
}
}
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
@Configuration
public class SecurityConfig {
@Resource
private LoginSuccessHandler loginSuccessHandler;
@Resource
private LoginFailHandler loginFailHandler;
@Resource
private LogoutSuccessHandler logoutSuccessHandler;
@Resource
private UserAuthenticationManager userAuthenticationManager;
@Resource
private AccessDeniedHandler accessDeniedHandler;
@Bean
public SecurityWebFilterChain filterChain(ServerHttpSecurity http) {
http.httpBasic()
.and()
.authorizeExchange()
.anyExchange()
.authenticated();
http.formLogin()
.authenticationManager(authenticationManager())
.authenticationSuccessHandler(loginSuccessHandler)
.authenticationFailureHandler(loginFailHandler)
.and()
.logout()
.logoutSuccessHandler(logoutSuccessHandler)
.and()
.exceptionHandling()
.accessDeniedHandler(accessDeniedHandler);
return http.build();
}
/**
* 注册用户信息验证管理器,可按需求添加多个按顺序执行
*/
@Bean
public ReactiveAuthenticationManager authenticationManager() {
LinkedList<ReactiveAuthenticationManager> managers = new LinkedList<>();
managers.add(userAuthenticationManager);
return new DelegatingReactiveAuthenticationManager(managers);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
自定义认证处理器
@Component
public class AuthenticationEntryPoint implements ServerAuthenticationEntryPoint {
@Override
public Mono<Void> commence(ServerWebExchange exchange, AuthenticationException e) {
return Mono.defer(() -> Mono.just(exchange.getResponse()).flatMap(response -> {
DataBufferFactory dataBufferFactory = response.bufferFactory();
DataBuffer dataBuffer = dataBufferFactory.wrap("Authentication fail".getBytes());
return response.writeWith(Mono.just(dataBuffer));
}));
}
}
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
@Configuration
public class SecurityConfig {
@Resource
private LoginSuccessHandler loginSuccessHandler;
@Resource
private LoginFailHandler loginFailHandler;
@Resource
private LogoutSuccessHandler logoutSuccessHandler;
@Resource
private UserAuthenticationManager userAuthenticationManager;
@Resource
private AccessDeniedHandler accessDeniedHandler;
@Resource
private AuthenticationEntryPoint authenticationEntryPoint;
@Bean
public SecurityWebFilterChain filterChain(ServerHttpSecurity http) {
http.httpBasic()
.and()
.authorizeExchange()
.anyExchange()
.authenticated();
http.formLogin()
.authenticationManager(authenticationManager())
.authenticationSuccessHandler(loginSuccessHandler)
.authenticationFailureHandler(loginFailHandler)
.and()
.logout()
.logoutSuccessHandler(logoutSuccessHandler)
.and()
.exceptionHandling()
.accessDeniedHandler(accessDeniedHandler)
.authenticationEntryPoint(authenticationEntryPoint);
return http.build();
}
/**
* 注册用户信息验证管理器,可按需求添加多个按顺序执行
*/
@Bean
public ReactiveAuthenticationManager authenticationManager() {
LinkedList<ReactiveAuthenticationManager> managers = new LinkedList<>();
managers.add(userAuthenticationManager);
return new DelegatingReactiveAuthenticationManager(managers);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
自定义鉴权处理器
@Slf4j
@Component
public class AuthorizeConfigManager implements ReactiveAuthorizationManager<AuthorizationContext> {
private final AntPathMatcher antPathMatcher = new AntPathMatcher();
@Override
public Mono<AuthorizationDecision> check(Mono<Authentication> authentication,
AuthorizationContext authorizationContext) {
return authentication.map(auth -> {
ServerWebExchange exchange = authorizationContext.getExchange();
ServerHttpRequest request = exchange.getRequest();
Collection<? extends GrantedAuthority> authorities = auth.getAuthorities();
for (GrantedAuthority authority : authorities) {
String authorityAuthority = authority.getAuthority();
String path = request.getURI().getPath();
if (antPathMatcher.match(authorityAuthority, path)) {
log.info(String.format("用户请求API校验通过,GrantedAuthority:{%s} Path:{%s} ", authorityAuthority, path));
return new AuthorizationDecision(true);
}
}
return new AuthorizationDecision(false);
}).defaultIfEmpty(new AuthorizationDecision(false));
}
@Override
public Mono<Void> verify(Mono<Authentication> authentication, AuthorizationContext object) {
return check(authentication, object)
.filter(AuthorizationDecision::isGranted)
.switchIfEmpty(Mono.defer(() -> Mono.error(new AccessDeniedException("Access Denied"))))
.flatMap(d -> Mono.empty());
}
}
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
@Configuration
public class SecurityConfig {
@Resource
private LoginSuccessHandler loginSuccessHandler;
@Resource
private LoginFailHandler loginFailHandler;
@Resource
private LogoutSuccessHandler logoutSuccessHandler;
@Resource
private UserAuthenticationManager userAuthenticationManager;
@Resource
private AccessDeniedHandler accessDeniedHandler;
@Resource
private AuthenticationEntryPoint authenticationEntryPoint;
@Resource
private AuthorizeConfigManager authorizeConfigManager;
@Bean
public SecurityWebFilterChain filterChain(ServerHttpSecurity http) {
http.httpBasic()
.and()
.authorizeExchange(e -> e
.anyExchange()
.access(authorizeConfigManager));
http.formLogin()
.authenticationManager(authenticationManager())
.authenticationSuccessHandler(loginSuccessHandler)
.authenticationFailureHandler(loginFailHandler)
.and()
.logout()
.logoutSuccessHandler(logoutSuccessHandler)
.and()
.exceptionHandling()
.accessDeniedHandler(accessDeniedHandler)
.authenticationEntryPoint(authenticationEntryPoint);
return http.build();
}
/**
* 注册用户信息验证管理器,可按需求添加多个按顺序执行
*/
@Bean
public ReactiveAuthenticationManager authenticationManager() {
LinkedList<ReactiveAuthenticationManager> managers = new LinkedList<>();
managers.add(userAuthenticationManager);
return new DelegatingReactiveAuthenticationManager(managers);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
SpringSecurity5(14-Gateway整合)的更多相关文章
- Spring Cloud Gateway 整合阿里 Sentinel网关限流实战!
大家好,我是不才陈某~ 这是<Spring Cloud 进阶>第八篇文章,往期文章如下: 五十五张图告诉你微服务的灵魂摆渡者Nacos究竟有多强? openFeign夺命连环9问,这谁受得 ...
- Springcloud gateway整合(集成)swagger2+finfe4j踩坑
项目使用gateway代替之前的zuul网关,需要整合swagger,踩了许多坑之后终于解决问题,话不多说直接上代码 因为使用的是阿里的东西所以注册中心选择了nacos,它的配置这里就不贴了 spri ...
- Spring Cloud Alibaba(14)---SpringCloudAlibaba整合Sleuth
SpringCloudAlibaba整合Sleuth 上一篇有写过Sleuth概述,Spring Cloud Alibaba(13)---Sleuth概述 这篇我们开始通过示例来演示链路追踪. 一.环 ...
- spring 5.x 系列第14篇 —— 整合RabbitMQ (代码配置方式)
源码Gitub地址:https://github.com/heibaiying/spring-samples-for-all 一.说明 1.1 项目结构说明 本用例关于rabbitmq的整合提供简单消 ...
- Spring Cloud Gateway(二):Spring Cloud Gateway整合Eureka应用
Spring Cloud Gateway 应用概述 下面的示例启动两个服务:gataway-server 和 user-service 都注册到注册中心 Eureka上,客户端请求后端服务[user- ...
- Spring Cloud Gateway整合Eureka
Spring Cloud Gateway features: Built on Spring Framework 5, Project Reactor and Spring Boot 2.0 Able ...
- gateway 整合 websocket demo
背景: 这个websocket 因为使用的地方不多,并没有独立出一个项目,是集成在已有的服务中. 1: gateway 配置 - id: service-test uri: lb:ws://se ...
- springcloud gateway整合sentinel
1.引入依赖 <parent> <groupId>org.springframework.boot</groupId> <artifactId>spri ...
- spring cloud gateway整合sentinel作网关限流
说明: sentinel可以作为各微服务的限流,也可以作为gateway网关的限流组件. spring cloud gateway有限流功能,但此处用sentinel来作为替待. 说明:sentine ...
- 物联网架构成长之路(14)-SpringBoot整合thymeleaf
使用thymeleaf作为模版进行测试 在pom.xml 增加依赖 <dependency> <groupId>org.springframework.boot</gro ...
随机推荐
- Hub PG walkthrough Easy
刚刚做了一个太难得简直看不懂 现在来做个简单的找回信心 nmap ┌──(root㉿kali)-[/home/ftpuserr] └─# nmap -p- -A 192.168.132.25 Star ...
- delphi编写sql脚本文件批量执行程序
程序使用DelphiXE11.1开发,用到控件UniDac9.1.1,QDAC里面的Qlog组件. 程序实现了SQL脚本文件批处理执行应用,运行效果图. 文件.pas代码 unit main; int ...
- 通过串口通信 对TCP传输层以下的理解
这可能是近期暂时最后一篇c嵌入式的文章了 基础的串口使用 参照网上的stm32教程套路引入标准库,初始化芯片手册上对应串口引脚 ,初始化stm32串口功能,然后有数据了就自然在寄存器上,就这样,你的波 ...
- Janus Pro:DeepSeek 开源革新,多模态 AI 的未来
Janus Pro 是 DeepSeek 开发的一个开源多模态人工智能框架,它通过集成视觉和语言处理能力,提供了高性能的多模态任务处理能力. 在线体验: https://deepseek-janusp ...
- 从装水瓶到接雨水:一道经典动态规划问题的深度解析|LeetCode 42 接雨水
LeetCode 42 接雨水 点此看全部题解 LeetCode必刷100题:一份来自面试官的算法地图(题解持续更新中) 生活中的算法 你有没有注意过,很多户外运动的水壶都有不规则的凹凸形状?这些凹凸 ...
- WitAwards 2024荣耀登榜!AOne载誉而归!
近日,FCIS 2024网络安全创新大会在上海举办.本次大会以"迈向安全服务化时代"为主题,邀请来自全球的网安精英.技术专家.CISO/CSO.白帽子.创业者等展开深度对话,分享与 ...
- 内容分发网络 CDN 概述
本文分享自天翼云开发者社区<内容分发网络 CDN 概述>,作者:Jerry CDN(Content Delivery Network)是一种分布式网络架构,旨在提供高效.可靠地将内容传送给 ...
- RabbitMQ(十)——消息优先级
RabbitMQ系列 RabbitMQ(一)--简介 RabbitMQ(二)--模式类型 RabbitMQ(三)--简单模式 RabbitMQ(四)--工作队列模式 RabbitMQ(五)--发布订阅 ...
- redis的连接池和管道
NoSQL泛指非关系型的数据库 非关系型数据库和关系型数据库的差别: 性能NOSQL是基于键值对的,可以想象成表中的主键和值的对应关系,而且不需要经过SQL层的解析,所以性能非常高 可扩展性同样也 ...
- [MQ] Kafka
概述: Kafka 安装指南 安装 on Windows Step1 安装 JDK JDK 安装后: 在"系统变量"中,找到 JAVA_HOME,如果没有则新建,将其值设置为 JD ...