说在前面
架构
- 前后端分离的工程,登录不用spring-cloud-security默认的表单,用restful风格的post请求,登录成功后创建认证和授权信息(代码里就是 UsernamePasswordAuthenticationToken),然后之后所有的请求都带 access_token 请求头过来进行认证和授权。
- 缓存用redis_cluster,数据库就mysql。
表结构
工程代码里的sql文件夹里,简单的写入一条用户,一个role(admin),和相关的关联关系。
先看效果
登录,成功返回token
?带上登录返回的token,请求/demo,正确返回
胡乱修改token,/demo请求不能通过认证
?
?把token恢复正确,胡乱改权限,/demo请求返回没有授权
?
?
我的思路
package com.faith.securitybaseonwebflux.security;
import com.faith.securitybaseonwebflux.security.authorization.FunpayAuthorizeExchangeSpecCustomizer;
import com.faith.securitybaseonwebflux.security.contextrepository.FunpaySecurityContextRepository;
import com.faith.securitybaseonwebflux.security.handler.FunpayAccessDeniedHandler;
import com.faith.securitybaseonwebflux.security.handler.FunpayAuthenticationEntryPointHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.server.SecurityWebFilterChain;
/**
* @author Leeko
* @date 2022/3/30
**/
@Configuration
@EnableWebFluxSecurity
public class FluxSecurityConfig {
@Autowired
FunpaySecurityContextRepository funpaySecurityContextRepository;
@Autowired
FunpayAccessDeniedHandler funpayAccessDeniedHandler;
@Autowired
FunpayAuthenticationEntryPointHandler funpayAuthenticationEntryPointHandler;
@Autowired
FunpayAuthorizeExchangeSpecCustomizer funpayAuthorizeExchangeSpecCustomizer;
public static final String[] AUTH_WHITELIST = new String[]{"/login", "/logout"};
@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
http.csrf().disable();
http.httpBasic().disable();
http.securityContextRepository(funpaySecurityContextRepository);
http.authorizeExchange(funpayAuthorizeExchangeSpecCustomizer)
.exceptionHandling().authenticationEntryPoint(funpayAuthenticationEntryPointHandler)
.and()
.exceptionHandling().accessDeniedHandler(funpayAccessDeniedHandler);
return http.build();
}
/**
* BCrypt密码编码
*
* @return
*/
@Bean
public BCryptPasswordEncoder bcryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
}
方法 securityWebFilterChain 的最后一行 http.build(),什么也不配置的时候,点进去跟一下代码,发现他默认的过滤器:
?发现第三个WebFilter在认证之前,而这个ReactorContextWebFilter 点进去看源码是修改上下文
ReactiveSecurityContextHolder的,那应该可以在这一步创建认证信息,然后也放入上下文,后来试了可以。
我不想在配置的方法里写那么长的代码,发现在 http.build 里有属性 AuthorizaExchangeSpec,build方法里用它来配置,那就单独写一个授权指定类?FunpayAuthorizeExchangeSpecCustomizer
总之,就开始什么都不配置,跟源码进去看人家怎么配的,看哪些地方可以自定义,就试之无他。
疑问
- spring-boot-security 的时候可以在方法上 @PreAuthorize来指定权限,为什么在spring-cloud-security不这么用,我记得spring-boot-security的对方法的鉴权是基于拦截器的,而拦截器是servlet的东西,webflux没有这一套,所以。。。懒得跟代码去确定了,欢迎小伙伴指正。
代码仓库
https://gitee.com/lijinfeigreen/myspringio/tree/master/myspringio/securitybaseonwebflux
|