目錄
1. OAuth2.0授權(quán)服務(wù)
2. 資源服務(wù)
3. Gateway網(wǎng)關(guān)
4. 測(cè)試
?
在SpringSecurity+OAuth2.0 搭建認(rèn)證中心和資源服務(wù)中心-CSDN博客???????
基礎(chǔ)上整合網(wǎng)關(guān)和JWT實(shí)現(xiàn)分布式統(tǒng)一認(rèn)證授權(quán)。
?
大致流程如下:
1、客戶(hù)端發(fā)出請(qǐng)求給網(wǎng)關(guān)獲取令牌
2、網(wǎng)關(guān)收到請(qǐng)求,直接轉(zhuǎn)發(fā)給授權(quán)服務(wù)
3、授權(quán)服務(wù)驗(yàn)證用戶(hù)名、密碼等一系列身份,通過(guò)則頒發(fā)令牌給客戶(hù)端
4、客戶(hù)端攜帶令牌請(qǐng)求資源,請(qǐng)求直接到了網(wǎng)關(guān)層
5、網(wǎng)關(guān)對(duì)令牌進(jìn)行校驗(yàn)(驗(yàn)簽、過(guò)期時(shí)間校驗(yàn)....)、鑒權(quán)(對(duì)當(dāng)前令牌攜帶的權(quán)限)和訪問(wèn)資源所需的權(quán)限進(jìn)行比對(duì),如果權(quán)限有交集則通過(guò)校驗(yàn),直接轉(zhuǎn)發(fā)給微服務(wù)
6、微服務(wù)進(jìn)行邏輯處理
1. OAuth2.0授權(quán)服務(wù)
導(dǎo)入依賴(lài)
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<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-oauth2</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-resource-server</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
application.yaml
server:
port: 8080
spring:
application:
name: oauth2-cloud-auth-server
cloud:
nacos:
## 注冊(cè)中心配置
discovery:
# nacos的服務(wù)地址,nacos-server中IP地址:端口號(hào)
server-addr: 127.0.0.1:8848
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/rbac?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
username: root
password: 123456
?這里展示部分代碼
AccessTokenConfig類(lèi)
/**
* 令牌的配置
*/
@Configuration
public class AccessTokenConfig {
/**
* JWT的秘鑰
* TODO 實(shí)際項(xiàng)目中需要統(tǒng)一配置到配置文件中,資源服務(wù)也需要用到
*/
private final static String SIGN_KEY="jwt";
/**
* 令牌的存儲(chǔ)策略
*/
@Bean
public TokenStore tokenStore() {
//使用JwtTokenStore生成JWT令牌
return new JwtTokenStore(jwtAccessTokenConverter());
}
/**
* JwtAccessTokenConverter
* TokenEnhancer的子類(lèi),在JWT編碼的令牌值和OAuth身份驗(yàn)證信息之間進(jìn)行轉(zhuǎn)換。
* TODO:后期可以使用非對(duì)稱(chēng)加密
*/
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter(){
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
// 設(shè)置秘鑰
converter.setSigningKey(SIGN_KEY);
return converter;
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
MyAuthorizationConfig類(lèi)
@Configuration
@EnableAuthorizationServer
public class MyAuthorizationConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private TokenStore tokenStore;
/**
* 客戶(hù)端存儲(chǔ)策略,這里使用內(nèi)存方式,后續(xù)可以存儲(chǔ)在數(shù)據(jù)庫(kù)
*/
@Autowired
private ClientDetailsService clientDetailsService;
/**
* Security的認(rèn)證管理器,密碼模式需要用到
*/
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private JwtAccessTokenConverter jwtAccessTokenConverter;
/**
* 配置令牌訪問(wèn)的安全約束
*/
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security
//開(kāi)啟/oauth/token_key驗(yàn)證端口權(quán)限訪問(wèn)
.tokenKeyAccess("permitAll()")
//開(kāi)啟/oauth/check_token驗(yàn)證端口認(rèn)證權(quán)限訪問(wèn)
.checkTokenAccess("permitAll()")
//表示支持 client_id 和 client_secret 做登錄認(rèn)證
.allowFormAuthenticationForClients();
}
//配置客戶(hù)端
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
//內(nèi)存模式
clients.inMemory()
//客戶(hù)端id
.withClient("test")
//客戶(hù)端秘鑰
.secret(new BCryptPasswordEncoder().encode("123456"))
//資源id,唯一,比如訂單服務(wù)作為一個(gè)資源,可以設(shè)置多個(gè)
.resourceIds("order")
//授權(quán)模式,總共四種,1. authorization_code(授權(quán)碼模式)、password(密碼模式)、client_credentials(客戶(hù)端模式)、implicit(簡(jiǎn)化模式)
//refresh_token并不是授權(quán)模式,
.authorizedGrantTypes("authorization_code","password","client_credentials","implicit","refresh_token")
//允許的授權(quán)范圍,客戶(hù)端的權(quán)限,這里的all只是一種標(biāo)識(shí),可以自定義,為了后續(xù)的資源服務(wù)進(jìn)行權(quán)限控制
.scopes("all")
//false 則跳轉(zhuǎn)到授權(quán)頁(yè)面
.autoApprove(false)
//授權(quán)碼模式的回調(diào)地址
.redirectUris("http://www.baidu.com"); //可以and繼續(xù)添加客戶(hù)端
}
@Bean
public AuthorizationServerTokenServices tokenServices() {
DefaultTokenServices services = new DefaultTokenServices();
//客戶(hù)端端配置策略
services.setClientDetailsService(clientDetailsService);
//支持令牌的刷新
services.setSupportRefreshToken(true);
//令牌服務(wù)
services.setTokenStore(tokenStore);
//access_token的過(guò)期時(shí)間
services.setAccessTokenValiditySeconds(60 * 60 * 2);
//refresh_token的過(guò)期時(shí)間
services.setRefreshTokenValiditySeconds(60 * 60 * 24 * 3);
//設(shè)置令牌增強(qiáng),使用jwt
services.setTokenEnhancer(jwtAccessTokenConverter);
return services;
}
/**
* 授權(quán)碼模式的service,使用授權(quán)碼模式authorization_code必須注入
*/
@Bean
public AuthorizationCodeServices authorizationCodeServices() {
//授權(quán)碼存在內(nèi)存中
return new InMemoryAuthorizationCodeServices();
}
/**
* 配置令牌訪問(wèn)的端點(diǎn)
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
//授權(quán)碼模式所需要的authorizationCodeServices
.authorizationCodeServices(authorizationCodeServices())
//密碼模式所需要的authenticationManager
.authenticationManager(authenticationManager)
//令牌管理服務(wù),無(wú)論哪種模式都需要
.tokenServices(tokenServices())
//只允許POST提交訪問(wèn)令牌,uri:/oauth/token
.allowedTokenEndpointRequestMethods(HttpMethod.POST);
}
}
SecurityConfig類(lèi)
/**
* spring security的安全配置
*/
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
/**
* 加密算法
*/
@Autowired
JwtTokenUserDetailsService userDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception {
//todo 允許表單登錄
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.loginProcessingUrl("/login")
.permitAll()
.and()
.csrf()
.disable();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//從數(shù)據(jù)庫(kù)中查詢(xún)用戶(hù)信息
auth.userDetailsService(userDetailsService);
}
/**
* AuthenticationManager對(duì)象在OAuth2認(rèn)證服務(wù)中要使用,提前放入IOC容器中
* Oauth的密碼模式需要
*/
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
2. 資源服務(wù)
導(dǎo)入依賴(lài)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.78</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
application.yaml
server:
port: 8081
spring:
application:
name: oauth2-cloud-service
cloud:
nacos:
## 注冊(cè)中心配置
discovery:
# nacos的服務(wù)地址,nacos-server中IP地址:端口號(hào)
server-addr: 127.0.0.1:8848
?AuthenticationFilter類(lèi)
@Component
public class AuthenticationFilter extends OncePerRequestFilter {
/**
* 具體方法主要分為兩步
* 1. 解密網(wǎng)關(guān)傳遞的信息
* 2. 將解密之后的信息封裝放入到request中
*/
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
//獲取請(qǐng)求頭中的用戶(hù)信息
String token = request.getHeader("token");
if (token!=null){
//解密
String json = Base64.decodeStr(token);
JSONObject jsonObject = JSON.parseObject(json);
//獲取用戶(hù)身份信息、權(quán)限信息
String principal = jsonObject.getString("user_name");
JSONArray tempJsonArray = jsonObject.getJSONArray("authorities");
//權(quán)限
String[] authorities = tempJsonArray.toArray(new String[0]);
//放入LoginVal
LoginVal loginVal = new LoginVal();
loginVal.setUsername(principal);
loginVal.setAuthorities(authorities);
//放入request的attribute中
request.setAttribute("login_message",loginVal);
}
filterChain.doFilter(request,response);
}
}
ServiceController類(lèi)
@RestController
public class ServiceController {
@RequestMapping("/test")
public LoginVal test(HttpServletRequest httpServletRequest){
return (LoginVal)httpServletRequest.getAttribute("login_message");
}
}
3. Gateway網(wǎng)關(guān)
導(dǎo)入依賴(lài)
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<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-oauth2</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-resource-server</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.78</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
</dependencies>
application.yaml
server:
port: 7000
spring:
main:
allow-bean-definition-overriding: true
application:
name: oauth2-cloud-gateway
cloud:
nacos:
## 注冊(cè)中心配置
discovery:
# nacos的服務(wù)地址,nacos-server中IP地址:端口號(hào)
server-addr: 127.0.0.1:8848
gateway:
## 路由
routes:
## id只要唯一即可,名稱(chēng)任意
- id: oauth2-cloud-auth-server
uri: lb://oauth2-cloud-auth-server
predicates:
## Path Route Predicate Factory斷言
- Path=/oauth/**
- id: oauth2-cloud-order
uri: lb://oauth2-cloud-service
predicates:
## Path Route Predicate Factory斷言
- Path=/test/**
oauth2:
cloud:
sys:
parameter:
ignoreUrls:
- /oauth/token
- /oauth/authorize
?AccessTokenConfig類(lèi)
/**
* 令牌的配置
*/
@Configuration
public class AccessTokenConfig {
private final static String SIGN_KEY="jwt";
/**
* 令牌的存儲(chǔ)策略
*/
@Bean
public TokenStore tokenStore() {
//使用JwtTokenStore生成JWT令牌
return new JwtTokenStore(jwtAccessTokenConverter());
}
/**
* JwtAccessTokenConverter
* TokenEnhancer的子類(lèi),在JWT編碼的令牌值和OAuth身份驗(yàn)證信息之間進(jìn)行轉(zhuǎn)換。
* TODO:后期可以使用非對(duì)稱(chēng)加密
*/
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter(){
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
// 設(shè)置秘鑰
converter.setSigningKey(SIGN_KEY);
return converter;
}
}
JwtAccessManager類(lèi)
@Slf4j
@Component
//經(jīng)過(guò)認(rèn)證管理器JwtAuthenticationManager認(rèn)證成功后,就需要對(duì)令牌進(jìn)行鑒權(quán),如果該令牌無(wú)訪問(wèn)資源的權(quán)限,則不允通過(guò)。
public class JwtAccessManager implements ReactiveAuthorizationManager<AuthorizationContext> {
@Override
public Mono<AuthorizationDecision> check(Mono<Authentication> mono, AuthorizationContext authorizationContext) {
URI uri = authorizationContext.getExchange().getRequest().getURI();
//設(shè)計(jì)權(quán)限角色,這里簡(jiǎn)單寫(xiě)一下,實(shí)際上應(yīng)該從數(shù)據(jù)庫(kù)或者緩存中獲取
List<String> authorities = new ArrayList<>();
authorities.add("ROLE_admin");
//認(rèn)證通過(guò)且角色匹配的用戶(hù)可訪問(wèn)當(dāng)前路徑
return mono
//判斷是否認(rèn)證成功
.filter(Authentication::isAuthenticated)
//獲取認(rèn)證后的全部權(quán)限
.flatMapIterable(Authentication::getAuthorities)
.map(GrantedAuthority::getAuthority)
//如果權(quán)限包含則判斷為true
.any(authorities::contains)
.map(AuthorizationDecision::new)
.defaultIfEmpty(new AuthorizationDecision(false));
}
}
JwtAuthenticationManager類(lèi)
/**
* JWT認(rèn)證管理器,主要的作用就是對(duì)攜帶過(guò)來(lái)的token進(jìn)行校驗(yàn),比如過(guò)期時(shí)間,加密方式等
* 一旦token校驗(yàn)通過(guò),則交給鑒權(quán)管理器進(jìn)行鑒權(quán)
*/
@Component
public class JwtAuthenticationManager implements ReactiveAuthenticationManager {
/**
* 使用JWT令牌進(jìn)行解析令牌
*/
@Autowired
private TokenStore tokenStore;
@Override
public Mono<Authentication> authenticate(Authentication authentication) {
return Mono.justOrEmpty(authentication)
.filter(a -> a instanceof BearerTokenAuthenticationToken)
.cast(BearerTokenAuthenticationToken.class)
.map(BearerTokenAuthenticationToken::getToken)
.flatMap((accessToken -> {
OAuth2AccessToken oAuth2AccessToken = this.tokenStore.readAccessToken(accessToken);
//根據(jù)access_token從數(shù)據(jù)庫(kù)獲取不到OAuth2AccessToken
if (oAuth2AccessToken == null) {
return Mono.error(new InvalidTokenException("無(wú)效的token!"));
} else if (oAuth2AccessToken.isExpired()) {
return Mono.error(new InvalidTokenException("token已過(guò)期!"));
}
OAuth2Authentication oAuth2Authentication = this.tokenStore.readAuthentication(accessToken);
if (oAuth2Authentication == null) {
return Mono.error(new InvalidTokenException("無(wú)效的token!"));
} else {
return Mono.just(oAuth2Authentication);
}
})).cast(Authentication.class);
}
}
SecurityConfig類(lèi)
@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {
/**
* JWT的鑒權(quán)管理器
*/
@Autowired
private ReactiveAuthorizationManager<AuthorizationContext> accessManager;
@Autowired
private RequestAuthenticationEntryPoint requestAuthenticationEntryPoint;
@Autowired
private RequestAccessDeniedHandler requestAccessDeniedHandler;
/**
* 系統(tǒng)參數(shù)配置
*/
@Autowired
private SysParameterConfig sysConfig;
/**
* token校驗(yàn)管理器
*/
@Autowired
private ReactiveAuthenticationManager tokenAuthenticationManager;
@Autowired
private CorsFilter corsFilter;
@Bean
SecurityWebFilterChain webFluxSecurityFilterChain(ServerHttpSecurity http) throws Exception{
//認(rèn)證過(guò)濾器,放入認(rèn)證管理器tokenAuthenticationManager
AuthenticationWebFilter authenticationWebFilter = new AuthenticationWebFilter(tokenAuthenticationManager);
authenticationWebFilter.setServerAuthenticationConverter(new ServerBearerTokenAuthenticationConverter());
http
.httpBasic().disable()
.csrf().disable()
.authorizeExchange()
//白名單直接放行
.pathMatchers(ArrayUtil.toArray(sysConfig.getIgnoreUrls(),String.class)).permitAll()
//其他的請(qǐng)求必須鑒權(quán),使用鑒權(quán)管理器
.anyExchange().access(accessManager)
//異常處理
.and().exceptionHandling()
.authenticationEntryPoint(requestAuthenticationEntryPoint)
.accessDeniedHandler(requestAccessDeniedHandler)
.and()
// 跨域過(guò)濾器
.addFilterAt(corsFilter, SecurityWebFiltersOrder.CORS)
//token的認(rèn)證過(guò)濾器,用于校驗(yàn)token和認(rèn)證
.addFilterAt(authenticationWebFilter, SecurityWebFiltersOrder.AUTHENTICATION);
return http.build();
}
}
RequestAccessDeniedHandler
/**
* 自定義返回結(jié)果:沒(méi)有權(quán)限訪問(wèn)時(shí)
*/
@Component
public class RequestAccessDeniedHandler implements ServerAccessDeniedHandler {
@Override
public Mono<Void> handle(ServerWebExchange exchange, AccessDeniedException denied) {
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.OK);
response.getHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
String body= JSONUtil.toJsonStr(new ResultMsg(1005,"無(wú)權(quán)限訪問(wèn)",null));
DataBuffer buffer = response.bufferFactory().wrap(body.getBytes(Charset.forName("UTF-8")));
return response.writeWith(Mono.just(buffer));
}
}
GlobalAuthenticationFilter
/**
* 全局過(guò)濾器,對(duì)token的攔截,解析token放入header中,便于下游微服務(wù)獲取用戶(hù)信息
* 分為如下幾步:
* 1、白名單直接放行
* 2、校驗(yàn)token
* 3、讀取token中存放的用戶(hù)信息
* 4、重新封裝用戶(hù)信息,加密成功json數(shù)據(jù)放入請(qǐng)求頭中傳遞給下游微服務(wù)
*/
@Component
@Slf4j
public class GlobalAuthenticationFilter implements GlobalFilter, Ordered {
/**
* JWT令牌的服務(wù)
*/
@Autowired
private TokenStore tokenStore;
/**
* 系統(tǒng)參數(shù)配置
*/
@Autowired
private SysParameterConfig sysConfig;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String requestUrl = exchange.getRequest().getPath().value();
//1、白名單放行,比如授權(quán)服務(wù)、靜態(tài)資源.....
if (checkUrls(sysConfig.getIgnoreUrls(),requestUrl)){
return chain.filter(exchange);
}
//2、 檢查token是否存在
String token = getToken(exchange);
if (StringUtils.isBlank(token)) {
return invalidTokenMono(exchange);
}
//3 判斷是否是有效的token
OAuth2AccessToken oAuth2AccessToken;
try {
//解析token,使用tokenStore
oAuth2AccessToken = tokenStore.readAccessToken(token);
Map<String, Object> additionalInformation = oAuth2AccessToken.getAdditionalInformation();
System.out.println(additionalInformation);
//取出用戶(hù)身份信息
String user_name = additionalInformation.get("user_name").toString();
//獲取用戶(hù)權(quán)限
List<String> authorities = (List<String>) additionalInformation.get("authorities");
//將用戶(hù)名和權(quán)限進(jìn)行Base64加密
JSONObject jsonObject=new JSONObject();
jsonObject.put("user_name", user_name);
jsonObject.put("authorities",authorities);
String base = Base64.encode(jsonObject.toJSONString());
// ServerHttpRequest 中的 mutate 方法是用于創(chuàng)建一個(gè)修改后的請(qǐng)求對(duì)象的方法,而不改變?cè)颊?qǐng)求對(duì)象。這個(gè)方法是為了在處理請(qǐng)求過(guò)程中創(chuàng)建一個(gè)新的請(qǐng)求對(duì)象,以便進(jìn)行一些修改或增強(qiáng)。
ServerHttpRequest tokenRequest = exchange.getRequest().mutate().header("token",base).build();
ServerWebExchange build = exchange.mutate().request(tokenRequest).build();
return chain.filter(build);
} catch (InvalidTokenException e) {
//解析token異常,直接返回token無(wú)效
return invalidTokenMono(exchange);
}
}
@Override
public int getOrder() {
return 0;
}
/**
* 對(duì)url進(jìn)行校驗(yàn)匹配
*/
private boolean checkUrls(List<String> urls,String path){
AntPathMatcher pathMatcher = new AntPathMatcher();
for (String url : urls) {
if (pathMatcher.match(url,path))
return true;
}
return false;
}
/**
* 從請(qǐng)求頭中獲取Token
*/
private String getToken(ServerWebExchange exchange) {
String tokenStr = exchange.getRequest().getHeaders().getFirst("Authorization");
if (StringUtils.isBlank(tokenStr)) {
return null;
}
String token = tokenStr.split(" ")[1];
if (StringUtils.isBlank(token)) {
return null;
}
return token;
}
/**
* 無(wú)效的token
*/
private Mono<Void> invalidTokenMono(ServerWebExchange exchange) {
return buildReturnMono(ResultMsg.builder()
.code(1004)
.msg("無(wú)效的token")
.build(), exchange);
}
private Mono<Void> buildReturnMono(ResultMsg resultMsg, ServerWebExchange exchange) {
ServerHttpResponse response = exchange.getResponse();
byte[] bits = JSON.toJSONString(resultMsg).getBytes(StandardCharsets.UTF_8);
DataBuffer buffer = response.bufferFactory().wrap(bits);
response.setStatusCode(HttpStatus.UNAUTHORIZED);
response.getHeaders().add("Content-Type", "application/json;charset:utf-8");
return response.writeWith(Mono.just(buffer));
}
}
SysParameterConfig
@ConfigurationProperties(prefix = "oauth2.cloud.sys.parameter")
@Data
@Component
public class SysParameterConfig {
/**
* 白名單
*/
private List<String> ignoreUrls;
}
4. 測(cè)試
?文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-820212.html
代碼鏈接:Gateway+Springsecurity+OAuth2.0+JWT實(shí)現(xiàn)分布式統(tǒng)一認(rèn)證授權(quán)資源-CSDN文庫(kù)?文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-820212.html
到了這里,關(guān)于Gateway+Springsecurity+OAuth2.0+JWT 實(shí)現(xiàn)分布式統(tǒng)一認(rèn)證授權(quán)!的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!