Spring gateway + Oauth2實(shí)現(xiàn)單點(diǎn)登錄及詳細(xì)配置
場(chǎng)景:
按職能,鑒權(quán)系統(tǒng)需要?jiǎng)澐?網(wǎng)關(guān)(spring gateway) + 鑒權(quán)(auth-server)。本文通過(guò)實(shí)踐搭建鑒權(quán)系統(tǒng)。
spring gateway
首先引入pom依賴(lài)
1、resilience 熔斷器
2、gateway 網(wǎng)關(guān)
3、eureka client 服務(wù)注冊(cè)中心
4、lombok插件
5、actuator狀態(tài)監(jiān)控
<dependencies>
<!-- 熔斷器-->
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-feign</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Gateway -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- 注冊(cè)中心 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
application.yml配置
1、gateway信息
2、actuator狀態(tài)信息
3、配置eureka server地址及注冊(cè)信息
4、日志配置
5、獲取oauth2的jwt key
server:
port: 18890
spring:
application:
name: open-api-gateway
profiles:
active: local
cloud:
gateway:
discovery:
locator:
enabled: true
lower-case-service-id: true
globalcors:
corsConfigurations:
'[/**]':
allowedOrigins: "*"
allowedMethods: "*"
default-filters:
- AddRequestParameter=gateway_type, member
- AddRequestHeader=gateway_type, member
management:
endpoints:
web:
exposure:
include: "*"
endpoint:
health:
show-details: always
eureka:
instance:
prefer-ip-address: true
instance-id: ${spring.cloud.client.ip-address}:${server.port}
client:
service-url:
defaultZone: http://127.0.0.1:22001/eureka
logging:
level:
com.dq.edu: debug
com:
netflix:
discovery: error
spring:
security:
oauth2:
resourceserver:
jwt:
jwk-set-uri: http://127.0.0.1:18889/auth-server/private/jwk_public_key
gateway 項(xiàng)目目錄

核心內(nèi)容:security配置、PermissionFilter鑒權(quán)過(guò)濾器
1、security配置
package com.digquant.openapigateway.config;
import com.digquant.openapigateway.entity.Response;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder;
import org.springframework.security.oauth2.server.resource.web.server.ServerBearerTokenAuthenticationConverter;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.ServerAuthenticationEntryPoint;
import org.springframework.security.web.server.authorization.ServerAccessDeniedHandler;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.nio.charset.Charset;
@Slf4j
@Configuration
@AllArgsConstructor
@EnableWebFluxSecurity
public class SecurityConfig {
private final ReactiveJwtDecoder jwtDecoder;
@Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
http.cors().disable().csrf().disable();
http
.authorizeExchange()
.pathMatchers("/**").permitAll()
.pathMatchers("/**/public/**").permitAll()
.pathMatchers("/**/static/**").permitAll()
.pathMatchers("/*/oauth/**").permitAll()
.pathMatchers("/actuator/**").permitAll()
.pathMatchers(HttpMethod.OPTIONS).permitAll()
.anyExchange().authenticated()
.and()
.exceptionHandling()
.accessDeniedHandler(serverAccessDeniedHandler())
.authenticationEntryPoint(serverAuthenticationEntryPoint())
.and()
.oauth2ResourceServer()
.jwt()
.jwtDecoder(jwtDecoder)
.and()
.bearerTokenConverter(new ServerBearerTokenAuthenticationConverter());
return http.build();
}
@Bean
public ServerAccessDeniedHandler serverAccessDeniedHandler() {
return (exchange, denied) -> {
log.debug("沒(méi)有權(quán)限");
String errMsg = StringUtils.hasText(denied.getMessage()) ? denied.getMessage() : "沒(méi)有權(quán)限";
Response result = new Response(1, errMsg);
return create(exchange, result);
};
}
@Bean
public ServerAuthenticationEntryPoint serverAuthenticationEntryPoint() {
return (exchange, e) -> {
log.debug("認(rèn)證失敗");
String errMsg = StringUtils.hasText(e.getMessage()) ? e.getMessage() : "認(rèn)證失敗";
Response result = new Response(1, errMsg);
return create(exchange, result);
};
}
private Mono<Void> create(ServerWebExchange exchange, Response result) {
return Mono.defer(() -> Mono.just(exchange.getResponse()))
.flatMap(response -> {
response.getHeaders().setContentType(MediaType.APPLICATION_JSON_UTF8);
DataBufferFactory dataBufferFactory = response.bufferFactory();
DataBuffer buffer = dataBufferFactory.wrap(createErrorMsg(result));
return response.writeWith(Mono.just(buffer))
.doOnError(error -> DataBufferUtils.release(buffer));
});
}
private byte[] createErrorMsg(Response result) {
return result.getErrMsg().getBytes(Charset.defaultCharset());
}
}
總結(jié):
gateway是基于 WebFlux的響應(yīng)式編程框架,所以在使用securityConfig時(shí)采用的注解是@EnableWebFluxSecurity
2、PermissionFilter
package com.digquant.openapigateway.filter;
import com.digquant.openapigateway.utils.IStrings;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.server.resource.authentication.AbstractOAuth2TokenAuthenticationToken;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
import java.util.Objects;
@Slf4j
@Order
@Component
@AllArgsConstructor
public class PermissionFilter implements WebFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
return ReactiveSecurityContextHolder.getContext()
//排除沒(méi)有Token的
.filter(Objects::nonNull)
// //檢查該路徑是否需要權(quán)限
// .filter(var -> permissionStore.usingPermission(exchange.getRequest().getPath().value()))
.map(SecurityContext::getAuthentication)
.map(authentication -> (JwtAuthenticationToken) authentication)
.doOnNext(jwtAuthenticationToken -> {
String path = exchange.getRequest().getPath().value();
log.info("請(qǐng)求 uri {}", path);
})
.map(AbstractOAuth2TokenAuthenticationToken::getPrincipal)
.map(var -> (Jwt) var)
.map(jwt -> {
String tokenValue = jwt.getTokenValue();
ServerHttpRequest.Builder builder = exchange.getRequest().mutate();
builder.header(HttpHeaders.AUTHORIZATION, IStrings.splice("Bearer ", tokenValue));
ServerHttpRequest request = builder.build();
return exchange.mutate().request(request).build();
})
.defaultIfEmpty(exchange)
.flatMap(chain::filter);
}
}
總結(jié)
1、使用permissionStore來(lái)記錄uri的權(quán)限要求
2、獲取到j(luò)wtToken時(shí),處理token所攜帶的權(quán)限,用于匹配是否能請(qǐng)求對(duì)應(yīng)資源
OAuth2 項(xiàng)目目錄

pom依賴(lài)
1、eureka client
2、spring boot mvc
3、redis 用于存儲(chǔ)jwt
4、mysql用于記錄用戶(hù)資源權(quán)限
5、oauth2組件
6、httpclient fregn用于用戶(hù)登陸鑒權(quán)
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.21</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.18</version>
</dependency>
<!-- oauth2-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-jose</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<!-- HttpClient -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
<version>10.9</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
應(yīng)用配置
server:
port: 37766
spring:
application:
name: auth-server
mvc:
throw-exception-if-no-handler-found: true
profiles:
active: dev
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.digquant.enity.po
logging:
level:
com:
digquant:
dao: info
file:
path: /dq/log/new/auth-server
digquant:
authorization:
auth-jwt-jks: hq-jwt.jks
auth-jwt-key: hq-jwt
auth-jwt-password: hq940313
access-token-validity-seconds: 14400
refresh-token-validity-seconds: 86400
1、AuthorizationServerConfig配置
package com.digquant.config;
import com.digquant.dao.CustomRedisTokenStore;
import com.digquant.enity.JWTProperties;
import com.digquant.enity.Response;
import com.digquant.service.OAuthUserService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import java.io.IOException;
@Slf4j
@Configuration
@AllArgsConstructor
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
private final JWTProperties jwtProperties;
/**
* 注入權(quán)限驗(yàn)證控制器 支持 password grant type
*/
private final AuthenticationManager authenticationManager;
/**
* 數(shù)據(jù)源
*/
private final DataSource dataSource;
/**
* 開(kāi)啟refresh_token
*/
private final OAuthUserService userService;
/**
* 采用redis 存儲(chǔ)token
*/
private final RedisConnectionFactory redisConnectionFactory;
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.allowFormAuthenticationForClients()
.checkTokenAccess("permitAll()")
.tokenKeyAccess("permitAll()")
.authenticationEntryPoint(authenticationEntryPoint())
.accessDeniedHandler(accessDeniedHandler());
}
@Bean
public AccessDeniedHandler accessDeniedHandler() {
return (request, response, accessDeniedException) -> {
Response result = new Response(1, accessDeniedException.getMessage());
writerResponse(response, result, HttpStatus.FORBIDDEN.value());
};
}
@Bean
public AuthenticationEntryPoint authenticationEntryPoint() {
return (request, response, authException) -> {
Response result = new Response(1, authException.getMessage());
writerResponse(response, result, HttpStatus.UNAUTHORIZED.value());
};
}
private void writerResponse(HttpServletResponse response, Response result, int status) throws IOException {
response.setStatus(status);
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
response.setCharacterEncoding("UTF-8");
response.getWriter().print(result.getErrMsg());
response.getWriter().flush();
}
@Bean("redisTokenStore")
public TokenStore redisTokenStore() {
return new CustomRedisTokenStore(redisConnectionFactory);
}
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
jwtAccessTokenConverter.setKeyPair(keyStoreKeyFactory().getKeyPair(jwtProperties.getAuthJwtKey()));
return jwtAccessTokenConverter;
}
@Bean
public KeyStoreKeyFactory keyStoreKeyFactory() {
return new KeyStoreKeyFactory(new ClassPathResource(jwtProperties.getAuthJwtJks()), jwtProperties.getAuthJwtPassword().toCharArray());
}
@Bean
public DefaultTokenServices tokenServices() {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(redisTokenStore());
defaultTokenServices.setTokenEnhancer(jwtAccessTokenConverter());
defaultTokenServices.setSupportRefreshToken(true);
defaultTokenServices.setReuseRefreshToken(false);
defaultTokenServices.setAccessTokenValiditySeconds(jwtProperties.getAccessTokenValiditySeconds());
defaultTokenServices.setRefreshTokenValiditySeconds(jwtProperties.getRefreshTokenValiditySeconds());
return defaultTokenServices;
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
//開(kāi)啟密碼授權(quán)類(lèi)型
endpoints
.authenticationManager(authenticationManager)
//配置token存儲(chǔ)方式
.tokenStore(redisTokenStore())
//需要額外配置,用于refres_token
.userDetailsService(userService)
//
.tokenServices(tokenServices())
.accessTokenConverter(jwtAccessTokenConverter())
.exceptionTranslator(exceptionTranslator());
}
@Bean
public WebResponseExceptionTranslator exceptionTranslator() {
return exception -> {
return ResponseEntity.status(HttpStatus.OK).body(new OAuth2Exception(exception.getMessage()));
};
}
@Bean
public ClientDetailsService clientDetails() {
return new JdbcClientDetailsService(dataSource);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// clients.withClientDetails(clientDetails());
clients.inMemory()
.withClient("open_api")
.authorizedGrantTypes("password","refresh_token")
.authorities("USER")
.scopes("read", "write")
.resourceIds("auth-server")
.secret(new BCryptPasswordEncoder().encode("digquant"));
}
}
2、ResourceServerConfig 資源服務(wù)配置
package com.digquant.config;
import lombok.AllArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
@Order(6)
@Configuration
@AllArgsConstructor
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
private final AccessDeniedHandler accessDeniedHandler;
private final AuthenticationEntryPoint authenticationEntryPoint;
@Override
public void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http
.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint)
.and().authorizeRequests()
.antMatchers("/swagger-ui.html","/webjars/**").permitAll()
.antMatchers("/oauth/**").permitAll()
.antMatchers("/actuator/**").permitAll()
.antMatchers("/").permitAll()
.antMatchers(HttpMethod.OPTIONS).permitAll()
.anyRequest().permitAll();
}
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.authenticationEntryPoint(authenticationEntryPoint)
.accessDeniedHandler(accessDeniedHandler)
.resourceId("auth-server");
}
}
3、SecurityConfig配置
package com.digquant.config;
import com.digquant.service.CustomAuthenticationProvider;
import com.digquant.service.OAuthUserService;
import lombok.AllArgsConstructor;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Order(7)
@Configuration
@EnableWebSecurity
@AllArgsConstructor
@AutoConfigureAfter(ResourceServerConfig.class)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final OAuthUserService userService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable();
http.authorizeRequests()
.antMatchers("/oauth/**").permitAll()
.antMatchers("/public/**").permitAll()
.antMatchers("/actuator/**").permitAll()
.antMatchers("/private/**").permitAll()
.antMatchers("/").permitAll()
.antMatchers(HttpMethod.OPTIONS).permitAll()
.anyRequest().permitAll()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/favor.ico");
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider());
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationProvider authenticationProvider() {
CustomAuthenticationProvider provider = new CustomAuthenticationProvider()
.setUserDetailsService(userService)
.setPasswordEncoder(passwordEncoder());
provider.setHideUserNotFoundExceptions(false);
return provider;
}
}
4、JwkController 用于gateway 請(qǐng)求jwt私鑰
package com.digquant.controller;
import com.digquant.enity.JWTProperties;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory;
import org.springframework.web.bind.annotation.*;
import java.security.interfaces.RSAPublicKey;
import java.util.Map;
@Api(tags = "jwk")
@RestController
@RequestMapping("/private")
@AllArgsConstructor
public class JwkController {
private final KeyStoreKeyFactory keyStoreKeyFactory;
private final JWTProperties jwtProperties;
@ApiOperation("獲取jwk")
@PostMapping("/jwk_public_key")
public Map<String, Object> getKey() {
RSAPublicKey publicKey = (RSAPublicKey) keyStoreKeyFactory.getKeyPair(jwtProperties.getAuthJwtKey()).getPublic();
RSAKey key = new RSAKey.Builder(publicKey).build();
return new JWKSet(key).toJSONObject();
}
}
注意私鑰放到項(xiàng)目的resources目錄下

5、用戶(hù)鑒權(quán)服務(wù),獲取用戶(hù)信息
package com.digquant.service;
import com.digquant.enity.to.AuthenticationTO;
import com.digquant.enums.LoginType;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.List;
import java.util.Map;
@Slf4j
@Component
public class OAuthUserService implements UserDetailsService {
@Autowired(required = false)
private List<OAuthUserProcessor> oAuthUserProcessors;
public UserDetails loadUser(String username, UsernamePasswordAuthenticationToken authentication) {
AuthenticationTO authenticationTO = new AuthenticationTO();
authenticationTO.setUsername(username);
authenticationTO.setPassword((String) authentication.getCredentials());
Map map = (Map) authentication.getDetails();
String scope = (String) map.get("scope");
String grantType = (String) map.get("grant_type");
String clientId = (String) map.get("client_id");
authenticationTO.setScope(scope);
authenticationTO.setGrantType(grantType);
authenticationTO.setLoginType(LoginType.PASSWORD);
authenticationTO.setClientId(clientId);
if (log.isDebugEnabled()) {
log.debug("請(qǐng)求認(rèn)證參數(shù):{}", authenticationTO);
}
if (!CollectionUtils.isEmpty(oAuthUserProcessors)) {
//目前只支持客戶(hù)端密碼登錄方式
for (OAuthUserProcessor oAuthUserProcessor : oAuthUserProcessors) {
if (oAuthUserProcessor.support(authenticationTO)) {
UserDetails userDetails = oAuthUserProcessor.findUser(authenticationTO);
//TODO 需要加載OpenApi用戶(hù)的權(quán)限
loadAuthorities(userDetails, authenticationTO);
return userDetails;
}
}
}
throw new UsernameNotFoundException("用戶(hù)不存在");
}
private void loadAuthorities(UserDetails userDetails, AuthenticationTO authenticationTO) {
}
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
return null;
}
}
獲取token

refresh_token

到此這篇關(guān)于Spring gateway + Oauth2實(shí)現(xiàn)單點(diǎn)登錄的文章就介紹到這了,更多相關(guān)Spring gateway Oauth2單點(diǎn)登錄內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java中int轉(zhuǎn)string與string轉(zhuǎn)int的效率對(duì)比
這篇文章主要介紹了java中int轉(zhuǎn)string與string轉(zhuǎn)int的效率對(duì)比,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03
Spring Security CsrfFilter過(guò)濾器用法實(shí)例
這篇文章主要介紹了Spring Security CsrfFilter過(guò)濾器用法實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-11-11
聊聊java中引用數(shù)據(jù)類(lèi)型有哪些
這篇文章主要介紹了java中引用數(shù)據(jù)類(lèi)型有哪些,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10
Java集合之Comparable和Comparator接口詳解
Java提供了Comparable接口與Comparator接口,它們?yōu)閿?shù)組或集合中的元素提供了排序邏輯,實(shí)現(xiàn)此接口的對(duì)象數(shù)組或集合可以通過(guò)Arrays.sort或Collections.sort進(jìn)行自動(dòng)排序。本文將通過(guò)示例講講它們的使用,需要的可以參考一下2022-12-12
快速解決commons-fileupload組件無(wú)法處理自定義head信息的bug
問(wèn)題在于fileupload組件解析完自定義的head節(jié)點(diǎn)后,卻忘記傳遞到FileItemStreamImpl中了,稍作修訂,即可修正該bug2013-08-08
SpringBoot+MyBatisPlus+Vue 前后端分離項(xiàng)目快速搭建過(guò)程(后端)
這篇文章主要介紹了SpringBoot+MyBatisPlus+Vue 前后端分離項(xiàng)目快速搭建過(guò)程(后端),快速生成后端代碼、封裝結(jié)果集、增刪改查、模糊查找,畢設(shè)基礎(chǔ)框架,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-05-05
java實(shí)現(xiàn)抖音飛機(jī)大作戰(zhàn)
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)抖音飛機(jī)大作戰(zhàn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-04-04

