【无标题】

Spring Secuirty Oauth2实战二实现单点登录



SSO

单点登录(Single Sign On),简称为 SSO,是比较流行的企业业务整合的解决方案之一。SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。

提示:这里可以添加本文要记录的大概内容:

1. Spring Secuirty Oauth2实现单点登录

1.1 什么是单点登录

单点登录(Single Sign On),简称为 SSO,是比较流行的企业业务整合的解决方案之一。
它的用途在于,不管多么复杂的应用群,只要在用户权限范围内,那么就可以做到,用户只
需要登录一次就可以访问权限范围内的所有应用子系统。

1.2 单点登录常见实现方式

同域单点登录
适用场景:都是企业自己的系统,所有系统都使用同一个一级域名通过不同的二级域名来区

在这里插入图片描述
核心原理:

  1. 门户系统设置 Cookie 的 domain 为一级域名也就是 zlt.com,这样就可以共享门户
    的 Cookie 给所有的使用该域名(xxx.zlt.com)的系统
  2. 使用 Spring Session 等技术让所有系统共享 Session
  3. 这样只要门户系统登录之后无论跳转应用1或者应用2,都能通过门户 Cookie 中的
    sessionId 读取到 Session 中的登录信息实现单点登录

跨域单点登录
单点登录之间的系统域名不一样,例如第三方系统。由于域名不一样不能共享 Cookie 了,这
样就需要通过一个单独的授权服务(UAA)来做统一登录,并基于共享UAA的 Cookie 来实现单
点登录。
在这里插入图片描述
核心原理:

  1. 访问系统1判断未登录,则跳转到UAA系统请求授权
  2. 在UAA系统域名 sso.com 下的登录地址中输入用户名/密码完成登录
  3. 登录成功后UAA系统把登录信息保存到 Session 中,并在浏览器写入域为 sso.com
    的 Cookie
  4. 访问系统2判断未登录,则跳转到UAA系统请求授权
  5. 由于是跳转到UAA系统的域名 sso.com 下,所以能通过浏览器中UAA的 Cookie 读
    取到 Session 中之前的登录信息完成单点登录
    基于Oauth2跨域单点登录

在这里插入图片描述

1.3 Spring Secuirty Oauth2单点登录实战

Oauth2单点登录除了需要授权中心完成统一登录/授权逻辑之外,各个系统本身(sso客户端)
也需要实现以下逻辑:

  1. 拦截请求判断登录状态
  2. 与 UAA授权中心 通过 Oauth2授权码模式 交互完成登录/单点登录
  3. 保存用户登录信息
    以上逻辑只需使用一个 @EnableOAuth2Sso 注解即可实现
    创建客户端
    1)引入依赖
      <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

2)修改application.yml

server:
  port: 8081
    #防止Cookie冲突,冲突会导致登录验证不通过
  servlet:
    session:
      cookie:
        name: OAUTH2-CLIENT-SESSIONID${server.port}

#与授权服务器对应的配置
security:
  oauth2:
    client:
      client-id: client
      client-secret: 123123
      user-authorization-uri: http://localhost:8080/oauth/authorize
      access-token-uri:  http://localhost:8080/oauth/token
    resource:
      token-info-uri: http://localhost:8080/oauth/check_token

3)在启动类上添加@EnableOAuth2Sso注解来启用单点登录功能
@EnableOAuth2Sso单点登录的原理简单来说就是:标注有@EnableOAuth2Sso的OAuth2
Client应用在通过某种OAuth2授权流程获取访问令牌后(一般是授权码流程),通过访问令
牌访问userDetails用户明细这个受保护资源服务,获取用户信息后,将用户信息转换为
Spring Security上下文中的认证后凭证Authentication,从而完成标注有
@EnableOAuth2Sso的OAuth2 Client应用自身的登录认证的过程。整个过程是基于
OAuth2的SSO单点登录

@SpringBootApplication
@EnableOAuth2Sso
public class Oauth2SsoClientDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(Oauth2SsoClientDemoApplication.class, args);
    }

}

4)添加接口用于获取当前登录用户信息

@RestController
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/getCurrentUser")
    public Object getCurrentUser(Authentication authentication) {
        return authentication;
    }


}

创建授权服务器
1)修改授权服务器中的AuthorizationServerConfig类

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig3 extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        //允许表单认证
        security.allowFormAuthenticationForClients();
        //校验token
        security.checkTokenAccess("permitAll()");

    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {

        /**
         *授权码模式
         */
        clients.inMemory()
                //配置client_id
                .withClient("client")
                //配置client-secret
                .secret(passwordEncoder.encode("123123"))
                //配置访问token的有效期
                .accessTokenValiditySeconds(3600)
                //配置刷新token的有效期
                .refreshTokenValiditySeconds(864000)
                //配置redirect_uri,用于授权成功后跳转
                .redirectUris("http://localhost:8081/login",
                        "http://localhost:8082/login")
                //自动授权配置
                .autoApprove(true)
                //配置申请的权限范围
                .scopes("all")
                /**
                 * 配置grant_type,表示授权类型
                 * authorization_code: 授权码模式
                 */
                .authorizedGrantTypes("authorization_code");
    }

}

2)启动授权服务和客户端服务
测试: 访问客户端需要授权的接口http://localhost:8081/user/getCurrentUser
会跳转到授权服务的登录界面

在这里插入图片描述
成功登录之后:
在这里插入图片描述
3)模拟两个客户端8081,8082
修改application.yaml配置

server:
  port: 8082
    #防止Cookie冲突,冲突会导致登录验证不通过
  servlet:
    session:
      cookie:
        name: OAUTH2-CLIENT-SESSIONID${server.port}

修改授权服务器配置,配置多个跳转路径
1 //配置redirect_uri,用于授权成功后跳转
2 .redirectUris(“http://localhost:8081/login”,
3 “http://localhost:8082/login”)
8081登录成功之后,8082无需再次登录就可以访问
http://localhost:8082/user/getCurrentUser

1.4 Oauth2整合网关实现微服务单点登录

网关整合 OAuth2.0 有两种思路,一种是授权服务器生成令牌, 所有请求统一在网
关层验证,判断权限等操作;另一种是由各资源服务处理,网关只做请求转发。
比较常用的是第一种,把API网关作为OAuth2.0的资源服务器角色,实现接入客
户端权限拦截、令牌解析并转发当前登录用户信息给微服务,这样下游微服务就
不需要关心令牌格式解析以及OAuth2.0相关机制了。
网关在认证授权体系里主要负责两件事:
(1)作为OAuth2.0的资源服务器角色,实现接入方权限拦截。
(2)令牌解析并转发当前登录用户信息(明文token)给微服务
微服务拿到明文token(明文token中包含登录用户的身份和权限信息)后也需要做两
件事:
(1)用户授权拦截(看当前用户是否有权访问该资源)
(2)将用户信息存储进当前线程上下文(有利于后续业务逻辑随时获取当前用户
信息)
在这里插入图片描述
核心代码,网关自定义全局过滤器进行身份认证

@Component
@Order(0)
public class AuthenticationFilter implements GlobalFilter, InitializingBean {

    @Autowired
    private RestTemplate restTemplate;

    private static Set<String> shouldSkipUrl = new LinkedHashSet<>();
    @Override
    public void afterPropertiesSet() throws Exception {
        // 不拦截认证的请求
        shouldSkipUrl.add("/oauth/token");
        shouldSkipUrl.add("/oauth/check_token");
        shouldSkipUrl.add("/user/getCurrentUser");
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        String requestPath = exchange.getRequest().getURI().getPath();
        
        //不需要认证的url
        if(shouldSkip(requestPath)) {
            return chain.filter(exchange);
        }

        //获取请求头
        String authHeader = exchange.getRequest().getHeaders().getFirst("Authorization");

        //请求头为空
        if(StringUtils.isEmpty(authHeader)) {
            throw new RuntimeException("请求头为空");
        }

        TokenInfo tokenInfo=null;
        try {
            //获取token信息
            tokenInfo = getTokenInfo(authHeader);
        }catch (Exception e) {
            throw new RuntimeException("校验令牌异常");
        }
        // tokenInfo
        exchange.getAttributes().put("tokenInfo",tokenInfo);
        return chain.filter(exchange);
    }

    private boolean shouldSkip(String reqPath) {

        for(String skipPath:shouldSkipUrl) {
            if(reqPath.contains(skipPath)) {
                return true;
            }
        }
        return false;
    }

    private TokenInfo getTokenInfo(String authHeader) {
        // 往授权服务发请求 /oauth/check_token
        // 获取token的值
        String token = StringUtils.substringAfter(authHeader, "bearer ");

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        //必须 basicAuth clienId clientSecret
        headers.setBasicAuth(MDA.clientId, MDA.clientSecret);

        MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
        params.add("token", token);

        HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(params, headers);

        ResponseEntity<TokenInfo> response = restTemplate.exchange(MDA.checkTokenUrl, HttpMethod.POST, entity, TokenInfo.class);

        return response.getBody();
    }
}

2. JWT

OAuth 2.0是当前业界标准的授权协议,它的核心是若干个针对不同场景的令牌颁发和管理流
程;而JWT是一种轻量级、自包含的令牌,可用于在微服务间安全地传递用户信息。

2.1 什么是JWT

JSON Web Token(JWT)是一个开放的行业标准(RFC 7519),它定义了一种
简介的、自包含的协议格式,用于在通信双方传递json对象,传递的信息经过数
字签名可以被验证和信任。JWT可以使用HMAC算法或使用RSA的公钥/私钥对来
签名,防止被篡改。
官网: https://jwt.io
标准: https://tools.ietf.org/html/rfc7519
JWT令牌的优点:

  1. jwt基于json,非常方便解析。
  2. 可以在令牌中自定义丰富的内容,易扩展。
  3. 通过非对称加密算法及数字签名技术,JWT防止篡改,安全性高。
  4. 资源服务使用JWT可不依赖授权服务即可完成授权。
    缺点:
    JWT令牌较长,占存储空间比较大。

2.2 JWT组成

一个JWT实际上就是一个字符串,它由三部分组成,头部(header)、载荷
(payload)与签名(signature)。
在这里插入图片描述
头部(header)
头部用于描述关于该JWT的最基本的信息:类型(即JWT)以及签名所用的算法
(如HMACSHA256或RSA)等。

{
  "alg": "HS256",
  "typ": "JWT"
}

然后将头部进行base64加密(该加密是可以对称解密的),构成了第一部分:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

载荷(payload)
第二部分是载荷,就是存放有效信息的地方。这个名字像是特指飞机上承载的货
品,这些有效信息包含三个部分:
标准中注册的声明(建议但不强制使用)
iss: jwt签发者
sub: jwt所面向的用户
aud: 接收jwt的一方
exp: jwt的过期时间,这个过期时间必须要大于签发时间
nbf: 定义在什么时间之前,该jwt都是不可用的.
iat: jwt的签发时间
jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。

  • 公共的声明
    公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要
    的必要信息.但不建议添加敏感信息,因为该部分在客户端可解密.
  • 私有的声明
    私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,
    因为base64是对称解密的,意味着该部分信息可以归类为明文信息。
    定义一个payload:
{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}

然后将其进行base64加密,得到Jwt的第二部分:

eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ

签名(signature)
jwt的第三部分是一个签证信息,这个签证信息由三部分组成:

  • header (base64后的)
  • payload (base64后的)
  • secret(盐,一定要保密)
    这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的
    字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成
    了jwt的第三部分:
var encodedString = base64UrlEncode(header) + '.' +
base64UrlEncode(payload);

 var signature = HMACSHA256(encodedString, 'fox'); // khA7TNYc7_0iELcDyTc7gH
BZ_xfIcgbfpzUNWwQtzME

将这三部分用.连接成一个完整的字符串,构成了最终的jwt:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ik
pvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.khA7TNYc7_0iELcDyTc7gHBZ_xfIcgbfpzUNWwQt
zME

注意:secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是
用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,在任何场景都不
应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt
了。
如何应用
一般是在请求头里加入Authorization,并加上Bearer标注:

fetch('api/user/1', {
 headers: {
 'Authorization': 'Bearer ' + token
  }
})

服务端会验证token,如果验证通过就会返回相应的资源。整个流程就是这样的:
在这里插入图片描述

2.3 JJWT

JJWT是一个提供端到端的JWT创建和验证的Java库,永远免费和开源(Apache
License,版本2.0)。JJW很容易使用和理解。它被设计成一个以建筑为中心的流
畅界面,隐藏了它的大部分复杂性。
快速开始
引入依赖

 <!--JWT依赖-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>

创建token
创建测试类,生成token

public class JwtdemoApplicationTests {

    private static final String SECRETKEY="123123";

    @Test
    public void test() {
        //创建一个JwtBuilder对象
        JwtBuilder jwtBuilder = Jwts.builder()
                //声明的标识{"jti":"666"}
                .setId("666")
                //主体,用户{"sub":"Fox"}
                .setSubject("Fox")
                //创建日期{"ita":"xxxxxx"}
                .setIssuedAt(new Date())
                //设置过期时间   1分钟
                .setExpiration(new Date(System.currentTimeMillis()+60*1000))
                //直接传入map
                // .addClaims(map)
                .claim("roles","admin")
                .claim("logo","xxx.jpg")
                //签名手段,参数1:算法,参数2:盐
                .signWith(SignatureAlgorithm.HS256, SECRETKEY);
        //获取token
        String token = jwtBuilder.compact();
        System.out.println(token);

        //三部分的base64解密
        System.out.println("=========");
        String[] split = token.split("\\.");
        System.out.println(Base64Codec.BASE64.decodeToString(split[0]));
        System.out.println(Base64Codec.BASE64.decodeToString(split[1]));
        //无法解密
        System.out.println(Base64Codec.BASE64.decodeToString(split[2]));
    }

  

}

运行结果
在这里插入图片描述
token的验证解析
在web应用中由服务端创建了token然后发给客户端,客户端在下次向服务端发送
请求时需要携带这个token(这就好像是拿着一张门票一样),那服务端接到这个
token应该解析出token中的信息(例如用户id),根据这些信息查询数据库返回相
应的结果。

@Test
    public void testParseToken(){
        //token
        String token ="eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI2NjYiLCJzdWIiOiJGb3giLCJpYXQiOjE2NjM3Njc2NjUsImV4cCI6MTY2Mzc2NzcyNSwicm9sZXMiOiJhZG1pbiIsImxvZ28iOiJ4eHguanBnIn0.NnAEi4xUdbKs7VZo5AHV-vRUUyH6aAPZP0rnPnaZkQ4";
        //解析token获取载荷中的声明对象
        Claims claims = Jwts.parser()
                .setSigningKey(SECRETKEY)
                .parseClaimsJws(token)
                .getBody();

        System.out.println("id:"+claims.getId());
        System.out.println("subject:"+claims.getSubject());
        System.out.println("issuedAt:"+claims.getIssuedAt());

        DateFormat sf =new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("签发时间:"+sf.format(claims.getIssuedAt()));
        System.out.println("过期时间:"+sf.format(claims.getExpiration()));
        System.out.println("当前时间:"+sf.format(new Date()));

        System.out.println("roles:"+claims.get("roles"));
        System.out.println("logo:"+claims.get("logo"));
    }

在这里插入图片描述
token过期校验
有很多时候,我们并不希望签发的token是永久生效的,所以我们可以为token添
加一个过期时间。原因:从服务器发出的token,服务器自己并不做记录,就存在
一个弊端:服务端无法主动控制某个token的立刻失效。
在这里插入图片描述
当未过期时可以正常读取,当过期时会引发io.jsonwebtoken.ExpiredJwtException
异常。
在这里插入图片描述

2.4 Spring Security Oauth2整合JWT

整合JWT
在之前的spring security Oauth2的代码基础上修改
引入依赖

 <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-jwt</artifactId>
            <version>1.0.9.RELEASE</version>
        </dependency>
@Configuration
public class JwtTokenStoreConfig {

    @Bean
    public TokenStore jwtTokenStore(){
        return new JwtTokenStore(jwtAccessTokenConverter());
    }

    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter(){
        JwtAccessTokenConverter accessTokenConverter = new
                JwtAccessTokenConverter();
        //配置JWT使用的秘钥
        accessTokenConverter.setSigningKey("123123");
        return accessTokenConverter;
    }

    @Bean
    public JwtTokenEnhancer jwtTokenEnhancer() {
        return new JwtTokenEnhancer();
    }
}

在授权服务器配置中指定令牌的存储策略为JWT

public class AuthorizationServerConfig2 extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private AuthenticationManager authenticationManagerBean;

    @Autowired
    private UserService userService;

    @Autowired
    @Qualifier("jwtTokenStore")
    private TokenStore tokenStore;

    @Autowired
    private JwtAccessTokenConverter jwtAccessTokenConverter;

    @Autowired
    private JwtTokenEnhancer jwtTokenEnhancer;

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        //配置JWT的内容增强器
        TokenEnhancerChain enhancerChain = new TokenEnhancerChain();
        List<TokenEnhancer> delegates = new ArrayList<>();
        delegates.add(jwtTokenEnhancer);
        delegates.add(jwtAccessTokenConverter);
        enhancerChain.setTokenEnhancers(delegates);
        endpoints.authenticationManager(authenticationManagerBean) //使用密码模式需要配置
                .tokenStore(tokenStore)  //配置存储令牌策略
                .accessTokenConverter(jwtAccessTokenConverter)
                .tokenEnhancer(enhancerChain) //配置tokenEnhancer
                .reuseRefreshTokens(false)  //refresh_token是否重复使用
                .userDetailsService(userService) //刷新令牌授权包含对用户信息的检查
                .allowedTokenEndpointRequestMethods(HttpMethod.GET,HttpMethod.POST); //支持GET,POST请求
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        //允许表单认证
        security.allowFormAuthenticationForClients();
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {

        /**
         *授权码模式
         *http://localhost:8080/oauth/authorize?response_type=code&client_id=client&redirect_uri=http://www.baidu.com&scope=all
         *http://localhost:8080/oauth/authorize?response_type=code&client_id=client
         *
         * password模式
         *  http://localhost:8080/oauth/token?username=fox&password=123456&grant_type=password&client_id=client&client_secret=123123&scope=all
         *
         *
         *
         *  刷新令牌
         *  http://localhost:8080/oauth/token?grant_type=refresh_token&client_id=client&client_secret=123123&refresh_token=[refresh_token值]
         */

        clients.inMemory()
                //配置client_id
                .withClient("client")
                //配置client-secret
                .secret(passwordEncoder.encode("123123"))
                //配置访问token的有效期
                .accessTokenValiditySeconds(3600)
                //配置刷新token的有效期
                .refreshTokenValiditySeconds(864000)
                //配置redirect_uri,用于授权成功后跳转
                .redirectUris("http://www.baidu.com")
                //配置申请的权限范围
                .scopes("all")
                /**
                 * 配置grant_type,表示授权类型
                 * authorization_code: 授权码
                 * password: 密码
                 * client_credentials: 客户端
                 * refresh_token: 更新令牌
                 */
                .authorizedGrantTypes("authorization_code","password","refresh_token");
    }


}

扩展JWT中的存储内容
有时候我们需要扩展JWT中存储的内容,这里我们在JWT中扩展一个 key为
enhance,value为enhance info 的数据。
继承TokenEnhancer实现一个JWT内容增强器

public class JwtTokenEnhancer implements TokenEnhancer {

    @Override
    public OAuth2AccessToken enhance(OAuth2AccessToken accessToken,
                                     OAuth2Authentication authentication) {
        Map<String, Object> info = new HashMap<>();
        info.put("enhance", "enhance info");
        ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(info);
        return accessToken;
    }
}

解析JWT
添加依赖

 <!--JWT依赖-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>

修改UserController类,使用jjwt工具类来解析Authorization头中存储的JWT内容

@RestController
@RequestMapping("/user")
public class UserController {

//    @RequestMapping("/getCurrentUser")
//    public Object getCurrentUser(Authentication authentication) {
//        return authentication.getPrincipal();
//    }

    @GetMapping("/getCurrentUser")
    public Object getCurrentUser(Authentication authentication,
                                 HttpServletRequest request) {
        String header = request.getHeader("Authorization");
        String token = null;
        if(header!=null){
            token = header.substring(header.indexOf("bearer") + 7);
        }else {
            token = request.getParameter("access_token");
        }
        return Jwts.parser()
                .setSigningKey("123123".getBytes(StandardCharsets.UTF_8))
                .parseClaimsJws(token)
                .getBody();

    }
}

启动服务访问http://localhost:8080/oauth/token?username=fox&password=123456&grant_type=password&client_id=client&client_secret=123123&scope=all

返回信息

{"access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJmb3giLCJzY29wZSI6WyJhbGwiXSwiZXhwIjoxNjgxMDk4NzIyLCJhdXRob3JpdGllcyI6WyJhZG1pbiJdLCJqdGkiOiIwZjViNTU1Yi03YzBiLTQ1ZjQtYjgzNS1mN2VkNmVlNjU1YWUiLCJjbGllbnRfaWQiOiJjbGllbnQiLCJlbmhhbmNlIjoiZW5oYW5jZSBpbmZvIn0.6MhJt-x3bqgZR8a0nxrk6-SA0Rtqg-2NXeJY5n1yFB4","token_type":"bearer","refresh_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJmb3giLCJzY29wZSI6WyJhbGwiXSwiYXRpIjoiMGY1YjU1NWItN2MwYi00NWY0LWI4MzUtZjdlZDZlZTY1NWFlIiwiZXhwIjoxNjgxOTU5MTIyLCJhdXRob3JpdGllcyI6WyJhZG1pbiJdLCJqdGkiOiI3M2FiZDU3OC0wMmU2LTQ2ODItYjE0NS1jNWY5MjEwYjQ0MTMiLCJjbGllbnRfaWQiOiJjbGllbnQiLCJlbmhhbmNlIjoiZW5oYW5jZSBpbmZvIn0.rfMHKYYuxLNSgITEou4mFKUuGC64d9R99Qldwiur_lQ","expires_in":3599,"scope":"all","enhance":"enhance info","jti":"0f5b555b-7c0b-45f4-b835-f7ed6ee655ae"}

将令牌放入Authorization头中,访问如下地址获取信息:
http://localhost:8080/user/getCurrentUser

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值