溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

Spring gateway和Oauth2如何實(shí)現(xiàn)單點(diǎn)登錄

發(fā)布時(shí)間:2021-09-26 10:14:04 來(lái)源:億速云 閱讀:280 作者:小新 欄目:開(kāi)發(fā)技術(shù)

這篇文章主要介紹Spring gateway和Oauth2如何實(shí)現(xiàn)單點(diǎn)登錄,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!

場(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、獲取oauth3的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:
    oauth3:
      resourceserver:
        jwt:
          jwk-set-uri: http://127.0.0.1:18889/auth-server/private/jwk_public_key

gateway 項(xiàng)目目錄

Spring gateway和Oauth2如何實(shí)現(xiàn)單點(diǎn)登錄

核心內(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.oauth3.jwt.ReactiveJwtDecoder;
import org.springframework.security.oauth3.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()
                .oauth3ResourceServer()
                .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.oauth3.jwt.Jwt;
import org.springframework.security.oauth3.server.resource.authentication.AbstractOAuth3TokenAuthenticationToken;
import org.springframework.security.oauth3.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(AbstractOAuth3TokenAuthenticationToken::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)資源

OAuth3 項(xiàng)目目錄

Spring gateway和Oauth2如何實(shí)現(xiàn)單點(diǎn)登錄

pom依賴(lài)

1、eureka client
2、spring boot mvc
3、redis 用于存儲(chǔ)jwt
4、mysql用于記錄用戶(hù)資源權(quán)限
5、oauth3組件
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>

     <!--        oauth3-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth3</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-oauth3-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.oauth3.common.exceptions.OAuth3Exception;
import org.springframework.security.oauth3.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth3.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth3.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth3.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth3.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth3.provider.ClientDetailsService;
import org.springframework.security.oauth3.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth3.provider.error.WebResponseExceptionTranslator;
import org.springframework.security.oauth3.provider.token.DefaultTokenServices;
import org.springframework.security.oauth3.provider.token.TokenStore;
import org.springframework.security.oauth3.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth3.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 OAuth3Exception(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.oauth3.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth3.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth3.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.oauth3.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目錄下

Spring gateway和Oauth2如何實(shí)現(xiàn)單點(diǎn)登錄

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

Spring gateway和Oauth2如何實(shí)現(xiàn)單點(diǎn)登錄

refresh_token

Spring gateway和Oauth2如何實(shí)現(xiàn)單點(diǎn)登錄

以上是“Spring gateway和Oauth2如何實(shí)現(xiàn)單點(diǎn)登錄”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI