场景:

按职能,鉴权系统需要划分 网关(spring gateway) + 鉴权(auth-server)。本文通过实践搭建鉴权系统。

spring gateway

首先引入pom依赖

1、resilience 熔断器
2、gateway 网关
3、eureka client 服务注册中心
4、lombok插件
5、actuator状态监控

<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>

        <!-- 注册中心 -->
        <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状态信息
3、配置eureka server地址及注册信息
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 项目目录

核心内容:security配置、permissionfilter鉴权过滤器

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("没有权限");
            string errmsg = stringutils.hastext(denied.getmessage()) ? denied.getmessage() : "没有权限";
            response result = new response(1, errmsg);
            return create(exchange, result);
        };
    }

    @bean
    public serverauthenticationentrypoint serverauthenticationentrypoint() {
        return (exchange, e) -> {
            log.debug("认证失败");
            string errmsg = stringutils.hastext(e.getmessage()) ? e.getmessage() : "认证失败";
            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());
    }
}

总结:

gateway是基于 webflux的响应式编程框架,所以在使用securityconfig时采用的注解是@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()
                //排除没有token的
                .filter(objects::nonnull)
//                //检查该路径是否需要权限
//                .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("请求 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);
    }
}

总结
1、使用permissionstore来记录uri的权限要求
2、获取到jwttoken时,处理token所携带的权限,用于匹配是否能请求对应资源

oauth2 项目目录

pom依赖

1、eureka client
2、spring boot mvc
3、redis 用于存储jwt
4、mysql用于记录用户资源权限
5、oauth2组件
6、httpclient fregn用于用户登陆鉴权

 <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>

应用配置

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;

    /**
     * 注入权限验证控制器 支持 password grant type
     */
    private final authenticationmanager authenticationmanager;

    /**
     * 数据源
     */
    private final datasource datasource;

    /**
     * 开启refresh_token
     */
    private final oauthuserservice userservice;

    /**
     * 采用redis 存储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 {
        //开启密码授权类型
        endpoints
                .authenticationmanager(authenticationmanager)
                //配置token存储方式
                .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 资源服务配置

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 请求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();
    }

}

注意私钥放到项目的resources目录下

5、用户鉴权服务,获取用户信息

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("请求认证参数:{}", authenticationto);
        }
        if (!collectionutils.isempty(oauthuserprocessors)) {
            //目前只支持客户端密码登录方式
            for (oauthuserprocessor oauthuserprocessor : oauthuserprocessors) {
                if (oauthuserprocessor.support(authenticationto)) {
                    userdetails userdetails = oauthuserprocessor.finduser(authenticationto);
                    //todo 需要加载openapi用户的权限
                    loadauthorities(userdetails, authenticationto);
                    return userdetails;
                }
            }
        }
        throw new usernamenotfoundexception("用户不存在");
    }

    private void loadauthorities(userdetails userdetails, authenticationto authenticationto) {

    }

    @override
    public userdetails loaduserbyusername(string s) throws usernamenotfoundexception {
        return null;
    }
}

获取token

refresh_token

到此这篇关于spring gateway + oauth2实现单点登录的文章就介绍到这了,更多相关spring gateway oauth2单点登录内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!