精华内容
下载资源
问答
  • Spring boot集成token,接口对token进行校验,并使用token获取登录用户信息 1、缓存token、验证token信息 /** * 缓存token * @param userId * @param token */ public void setTokenUser(String userId, ...

    Spring boot集成token,接口对token进行校验,并使用token获取登录用户信息

    1、缓存token、验证token信息

     /**
         *  缓存token
         * @param userId
         * @param token
         */
        public void setTokenUser(String userId, String token) {
            // 缓存token
            /** token失效时间 18000 = 5小时 7200 = 2小时  3600 = 1小时 1800 = 半小时 900 = 15分钟 60 = 1分钟*/
            MapCache.single().set("tokenUser" + userId, token, 18000); // 两小时过期
            MapCache.single().set(token, getSysUser(), 18000); // 两小时过期
        }
    
        /**
         * 验证token信息
         *
         * @return User
         */
        public SysUser analyticalUser() {
            String token = null;
            try {
                token = getRequest().getHeader("accessToken");
            } catch (NoSuchMessageException e) {
                /** token失效状态 */
                throw new UserTokenInvalidException("10000", null, "无认证信息,请先登录");
            }
            if (token == null) {
                /** token失效状态 */
                throw new UserTokenInvalidException("10000", null, "无认证信息,请先登录");
            }
            SysUser user = MapCache.single().get(token);
            if (user == null) {
                /** token失效状态 */
                throw new UserTokenInvalidException("10000", null, "认证失效,请先登录");
            }
            /**
             * token缓存常量
             */
            String tokenVerify = MapCache.single().get("tokenUser" + user.getUserId());
            System.out.println(tokenVerify);
            if (!tokenVerify.equals(token)) {
                /** token失效状态 */
                throw new UserTokenInvalidException("10000", null, "登录失效,请先登录");
            }
            MapCache.single().set("tokenUser" + user.getUserId(), token, 18000); // 两小时过期
            MapCache.single().set(token, user, 18000);
            return user;
        }
    

    2、SysUser实体类

    /**
     * 用户对象 sys_user
     */
    public class SysUser extends BaseEntity
    {
        private static final long serialVersionUID = 1L;
    
        /** 用户ID */
        @Excel(name = "用户序号", cellType = ColumnType.NUMERIC, prompt = "用户编号")
        private Long userId;
    
        /** 部门ID */
        @Excel(name = "部门编号", type = Type.IMPORT)
        private Long deptId;
    
        /** 角色ID */
        private Long roleId;
    
        /** 登录名称 */
        @Excel(name = "登录名称")
        private String loginName;
    
        /** 用户名称 */
        @Excel(name = "用户名称")
        private String userName;
    
        /** 密码 */
        private String password;
    
        /** 盐加密 */
        private String salt;
    
        /** 帐号状态(0正常 1停用) */
        @Excel(name = "帐号状态", readConverterExp = "0=正常,1=停用")
        private String status;
    
        /** 删除标志(0代表存在 2代表删除) */
        private String delFlag;
    
        /** 密码最后更新时间 */
        private Date pwdUpdateDate;
    
        public SysUser()
        {
    
        }
    
        public SysUser(Long userId)
        {
            this.userId = userId;
        }
    }
    
    

    3、Map缓存实现工具类

    import java.util.Map;
    import java.util.concurrent.ConcurrentHashMap;
    
    /**
     * Map 缓存实现
     */
    public class MapCache {
    
        /**
         * 默认存储1024个缓存
         */
        private static final int DEFAULT_CACHES = 1024;
    
        private static final MapCache INS = new MapCache();
    
        public static MapCache single() {
            return INS;
        }
    
        /**
         * 缓存容器
         */
        private final Map<String, CacheObject> cachePool;
    
        public MapCache() {
            this(DEFAULT_CACHES);
        }
    
        public MapCache(int cacheCount) {
            cachePool = new ConcurrentHashMap<>(cacheCount);
        }
    
        /**
         * 读取一个缓存
         *
         * @param key 缓存key
         * @param <T>
         * @return
         */
        public <T> T get(String key) {
            CacheObject cacheObject = cachePool.get(key);
            if (null != cacheObject) {
                long cur = System.currentTimeMillis() / 1000;
                if (cacheObject.getExpired() <= 0 || cacheObject.getExpired() > cur) {
                    Object result = cacheObject.getValue();
                    return (T) result;
                }
            }
            return null;
        }
    
        /**
         * 读取一个hash类型缓存
         *
         * @param key   缓存key
         * @param field 缓存field
         * @param <T>
         * @return
         */
        public <T> T hget(String key, String field) {
            key = key + ":" + field;
            return this.get(key);
        }
    
        /**
         * 设置一个缓存
         *
         * @param key   缓存key
         * @param value 缓存value
         */
        public void set(String key, Object value) {
            this.set(key, value, -1);
        }
    
        /**
         * 设置一个缓存并带过期时间
         *
         * @param key     缓存key
         * @param value   缓存value
         * @param expired 过期时间,单位为秒
         */
        public void set(String key, Object value, long expired) {
            expired = expired > 0 ? System.currentTimeMillis() / 1000 + expired : expired;
            CacheObject cacheObject = new CacheObject(key, value, expired);
            cachePool.put(key, cacheObject);
        }
    
        /**
         * 设置一个hash缓存
         *
         * @param key   缓存key
         * @param field 缓存field
         * @param value 缓存value
         */
        public void hset(String key, String field, Object value) {
            this.hset(key, field, value, -1);
        }
    
        /**
         * 设置一个hash缓存并带过期时间
         *
         * @param key     缓存key
         * @param field   缓存field
         * @param value   缓存value
         * @param expired 过期时间,单位为秒
         */
        public void hset(String key, String field, Object value, long expired) {
            key = key + ":" + field;
            expired = expired > 0 ? System.currentTimeMillis() / 1000 + expired : expired;
            CacheObject cacheObject = new CacheObject(key, value, expired);
            cachePool.put(key, cacheObject);
        }
    
        /**
         * 根据key删除缓存
         *
         * @param key 缓存key
         */
        public void del(String key) {
            cachePool.remove(key);
        }
    
        /**
         * 根据key和field删除缓存
         *
         * @param key   缓存key
         * @param field 缓存field
         */
        public void hdel(String key, String field) {
            key = key + ":" + field;
            this.del(key);
        }
    
        /**
         * 清空缓存
         */
        public void clean() {
            cachePool.clear();
        }
    
        static class CacheObject {
            private final String key;
            private final Object value;
            private final long expired;
    
            public CacheObject(String key, Object value, long expired) {
                this.key = key;
                this.value = value;
                this.expired = expired;
            }
    
            public String getKey() {
                return key;
            }
    
            public Object getValue() {
                return value;
            }
    
            public long getExpired() {
                return expired;
            }
        }
    }
    

    4、自定义异常类

    import com.common.exception.base.BaseException;
    
    /**
     * 用户token相关错误
     */
    public class UserTokenInvalidException extends BaseException
    {
        private static final long serialVersionUID = 1L;
    
        public UserTokenInvalidException(String code, Object[] args, String message)
        {
            super("user token invalid", code, args, message);
        }
    
    }
    
    

    5、shiro 工具类

    /**
     * shiro 工具类
     */
    public class ShiroUtils
    {
        public static Subject getSubject()
        {
            return SecurityUtils.getSubject();
        }
    
        public static Session getSession()
        {
            return SecurityUtils.getSubject().getSession();
        }
    
        public static void logout()
        {
            getSubject().logout();
        }
    
        public static SysUser getSysUser()
        {
            SysUser user = null;
            Object obj = getSubject().getPrincipal();
            if (StringUtils.isNotNull(obj))
            {
                user = new SysUser();
                BeanUtils.copyBeanProp(user, obj);
            }
            return user;
        }
    
        public static void setSysUser(SysUser user)
        {
            Subject subject = getSubject();
            PrincipalCollection principalCollection = subject.getPrincipals();
            String realmName = principalCollection.getRealmNames().iterator().next();
            PrincipalCollection newPrincipalCollection = new SimplePrincipalCollection(user, realmName);
            // 重新加载Principal
            subject.runAs(newPrincipalCollection);
        }
    
        public static Long getUserId()
        {
            return getSysUser().getUserId().longValue();
        }
    
        public static String getLoginName()
        {
            return getSysUser().getLoginName();
        }
    
        public static String getIp()
        {
            return getSubject().getSession().getHost();
        }
    
        public static String getSessionId()
        {
            return String.valueOf(getSubject().getSession().getId());
        }
    
        /**
         * 生成随机盐
         */
        public static String randomSalt()
        {
            // 一个Byte占两个字节,此处生成的3字节,字符串长度为6
            SecureRandomNumberGenerator secureRandom = new SecureRandomNumberGenerator();
            String hex = secureRandom.nextBytes(3).toHex();
            return hex;
        }
    }
    
    

    6、登录 and 后端解析用户信息

    /**
         * pad端登录
         * @param username 账号
         * @param password 密码
         */
        @PostMapping("/login")
        @ResponseBody
        public AjaxResult login(@NotNull(message = "用户不能为空!")String username,
                                   @NotNull(message = "密码不能为空!")String password ,
                                   HttpServletRequest request) throws IOException {
            System.out.println("pad登录>>>>userName>>>"+username+">>>password>>>"+password);
            UsernamePasswordToken token = new UsernamePasswordToken(username, password, false);
            Subject subject = SecurityUtils.getSubject();
            try {
                //已有登录验证
                subject.login(token);
                //返回的实体
                loginDto dto = new loginDto();
                dto.setUserId(getUserId().toString());//用户ID
                dto.setToken(UUID.randomUUID().toString());//返回
                System.out.println("【登录获取token】{}"+dto.getToken());
                //缓存token
                setTokenUser(dto.getUserId(),dto.getToken());
                return AjaxResult.success(dto);
            } catch (AuthenticationException e) {
                String msg = "登录名或密码错误";
                return error(msg);
            }
        }
    
        @PostMapping("/getUser")
        @ResponseBody
        public AjaxResult getUser(){
            System.out.println("【解析访问用户信息】");
            SysUser user = analyticalUser();
            return AjaxResult.success(user);
        }
    

    7、请求接口时,headers请求头带有accessToken参数

    在这里插入图片描述

    展开全文
  • jwt Token验证与解析

    千次阅读 2019-01-06 13:02:00
    网上似乎没有相关代码 ...贴上一段Token解析认证 [TestMethod] public void TestMethod1() { string Token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJMb2dpblR5cGUiOiLlvq7kv6HnmbvlvZUiLCJJc09uZ...

    网上似乎没有相关代码

    贴上一段Token的解析认证

    [TestMethod]
            public void TestMethod1()
            {
                string Token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJMb2dpblR5cGUiOiLlvq7kv6HnmbvlvZUiLCJJc09uZSI6IkZhbHNlIiwiSUQiOiIxMDc2NDYyODY4OTQzMjEyNTQzIiwiUGhvbmUiOiIxMSIsIkVtYWlsIjoiMzMyMSIsIk9wZW5pZCI6IkJCIiwiTmFtZSI6IjEyMyIsIm5iZiI6MTU0Njc1MDQxOSwiZXhwIjoxNTQ2NzUyMjE5LCJpc3MiOiJUZXN0SXNzdWVyIiwiYXVkIjoiVGVzdEF1ZGllbmNlIn0._g3rfr2P3YEFRgKlxv_7DtnxkLq4CrfXBdEUHUDl9jc";
                /// 密匙
                string IssuerSigningKey = "AAAAAAAAAAAAAAAABBBBBBBBBVCCCCC==";
    
                /// 发行
                string ValidIssuer = "TestIssuer";
    
                /// 观众
                string ValidAudience = "TestAudience";
    
                var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(IssuerSigningKey));
                var tokenValidationParams = new TokenValidationParameters()
                {
                    ValidateLifetime = true,
                    ValidateAudience = true,
                    ValidateIssuer = true,
                    ValidateIssuerSigningKey = true,
                    ValidIssuer = ValidIssuer,
                    ValidAudience= ValidAudience,
                    IssuerSigningKey = secretKey,
                };
                var jwtTokenHandler = new JwtSecurityTokenHandler();
                var a = jwtTokenHandler.ValidateToken(Token, tokenValidationParams, out SecurityToken validated);
    
            }

     

    效果:

     

    转载于:https://www.cnblogs.com/AnAng/p/10228394.html

    展开全文
  • .net core Jwt token验证与jose token解析

    千次阅读 2020-10-13 18:49:59
    后端可以接收前端传入的token并使用jose进行解析 本篇主要讲解后端实现,前端token的存储与传递给后端方式,之后文章将会单独讲解 首先第一步,实现登录,并将登陆成功后的用户信息封装到token中,下面附代码:

    一般项目中对接登录需要token验证用户信息,最近架构了一套后端基于.net core的系统框架,下面把过程中集成jwt遇到的问题分享给大家。
    实现逻辑:

    1. 登录后利用jwt生成token包含用户基本信息返回给前端
    2. 前端拿到token后存储在前端,并且每次请求后端接口中传给后端
    3. 后端可以接收前端传入的token并使用jose进行解析
      本篇主要讲解后端实现,前端token的存储与传递给后端方式,之后文章将会单独讲解

    首先第一步,实现登录,并将登陆成功后的用户信息封装到token中,下面附代码:

            [AllowAnonymous]
            [HttpGet]
            public IActionResult Login(string userName, string pwd)
            {
                var pwdMd5 = Md5Helper.Md5(Md5Helper.Md5(pwd));
                if (!authService.AccountExist(userName, pwdMd5))
                {
                    return BadRequest(new { message = "用户名或者密码错误" });
                }
                var claims = new[]
                {
                      new Claim(JwtRegisteredClaimNames.Nbf,$"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}") ,
                      new Claim (JwtRegisteredClaimNames.Exp,$"{new DateTimeOffset(DateTime.Now.AddMinutes(30)).ToUnixTimeSeconds()}"),
                      new Claim(ClaimTypes.Name, userName),
                      new Claim("userId", "test"),
                      new Claim("name", userName)
                    };
                var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Const.SecurityKey));
                var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
                var token = new JwtSecurityToken(
                  issuer: Const.Domain,
                  audience: Const.Domain,
                  claims: claims,
                  expires: DateTime.Now.AddMinutes(30),
                  signingCredentials: creds);
    
                return Ok(new
                {
                    token = new JwtSecurityTokenHandler().WriteToken(token)
                });
            }
    

    登陆的实现不在此讲解,现在需要了解的是登录之后我们可以通过如下代码将部分登陆用户信息封装到token中

        var claims = new[]
                {
                      new Claim(JwtRegisteredClaimNames.Nbf,$"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}") ,
                      new Claim (JwtRegisteredClaimNames.Exp,$"{new DateTimeOffset(DateTime.Now.AddMinutes(30)).ToUnixTimeSeconds()}"),
                      new Claim(ClaimTypes.Name, userName),
                      new Claim("userId", "test"),
                      new Claim("name", userName)
                    };
                var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Const.SecurityKey));
                var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
                var token = new JwtSecurityToken(
                  issuer: Const.Domain,
                  audience: Const.Domain,
                  claims: claims,
                  expires: DateTime.Now.AddMinutes(30),
                  signingCredentials: creds);
    

    这里的 new Claim(“userId”, “test”)与 new Claim(“name”, userName)是封装的我们系统登陆用户的信息,传送到前端,当接口调用时也可以根据token中携带的这部分信息识别当前用户。
    另外 Const.SecurityKey是jwt加密的密钥, Const.Domain是站点地址
    配置如下

        /// <summary>
        /// jwt配置类
        /// </summary>
        public static class Const
        {
            public const string SecurityKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDI2a2EJ7m872v0afyoSDJT2o1+SitIeJSWtLJU8/Wz2m7gStexajkeD+Lka6DSTy8gt9UwfgVQo6uKjVLG5Ex7PiGOODVqAEghBuS7JzIYU5RvI543nNDAPfnJsas96mSA7L/mD7RTE2drj6hf3oZjJpMPZUQI/B1Qjb5H3K3PNwIDAQAB";
            /// <summary>
            /// 站点地址
            /// </summary>
            public const string Domain = "http://localhost:5000";
    
            public static string ValidAudience;
        }
    }
    

    封装完成后可以通过 new JwtSecurityTokenHandler().WriteToken(token)来利用封装的信息生成一个token,然后就把这个token返回给前端。

    接下来前端在调用接口时会将上一步拿到的token 附加到请求头header 的 Authorization字段中,
    后端在接收到接口请求时通过如下代码拿到请求中的token字符串

       var headers = _httpContextAccessor.HttpContext.Request.Headers["Authorization"];
    

    接下来 可以通过jose来解析 拿到的token字符串
    代码如下:

       public static Object decode2(string token) {
                var authInfo = Jose.JWT.Payload<UserInfo>(token.Replace("Bearer ", ""));
                return authInfo;
            }
    

    UserInfo是自定义的用户类,里边字段跟前面登陆成功封装到token的字段名称一致,用于接收解析成功的用户信息。
    这样便可以拿到登陆成功返回给前端,前端又传回来的token中的用户信息。

    加班中时间紧迫,jwt的集成和jose的安装将在之后讲解。

    展开全文
  • token 验证失败 可能的问题分析

    千次阅读 2015-07-02 23:39:00
    上面说了,原样返回echostr参数内容,可是如果你在返回echostr之前有任何输出,都将导致token验证失败,无法接入微信。 比如一些php的warning,notice之类的警告,还有一些空格之类的空白字符,都可能导致无法...

    真的得好好看文档,但是由于工作的需要,我们都在赶进度,其实慢下来,仔细看文档,会给你省不少时间。

    进入正题。

    请看微信接入指南

    233506_GlOR_1474258.png

    划横线的这一部分其实很重要,值得仔细推敲。

    上面说了,原样返回echostr参数内容,可是如果你在返回echostr之前有任何输出,都将导致token验证失败,无法接入微信。

    比如一些php的warning,notice之类的警告,还有一些空格之类的空白字符,都可能导致无法成功接入微信。

    转载于:https://my.oschina.net/zzqPHPer/blog/473818

    展开全文
  • python实现token解析

    千次阅读 2019-09-23 11:22:26
    产生条件 ... cookie 服务器给一个用户开辟出来的一段内存空间用于保存这次会话的一些内容,如果浏览器不支持Cookie(如大部分手机中的浏览器)或者把Cookie禁用了,Cookie功能就会失效 ...token 客户端收到 ...
  • 借鉴参考Java Token登录验证 使用jjwt生成和解析JWTjava基于token验证之登陆验证等什么是Token?我的理解来说 token就是你访问服务器的口令,只要token合法,正确,你就能获取到后端数据当用户第一次登陆后,用户名...
  • token生成和解析

    2021-03-08 11:55:50
    token 工作原理就是浏览器发送请求到后端生成一个token然后把token返回到前端 浏览器根据从后端传过来的token来进行验证如果通过就继续操作如果不是后台传过来的token值则需要重新登录 如果浏览器的token值过期则...
  • 引言 最近捣鼓RN,做了个项目,但是到调试接口的时候出了一...这些错误发生在你向服务器发送请求的时候,返回值不是JSON而你却用JSON的方法解析的时候,可能会发生这种情况 fetch(’/api’).then(res => res.json()) 这
  • 1. oauth2原始错误返回类型JSON格式为{"error": "invalid_token","error_description": "Invalid access token: 123123123"}2. 想要在返回的数据类型中加上一个字段3.源码中源码org.springframework.security.oauth2...
  • } catch (Exception e) { log.error("解析token错误", e); throw new BusinessException("解析token错误"); } } // 如果jwt令牌通过了检测, 那么就把request传递给后面的RESTful api ...
  • C# 生成校验解析token

    千次阅读 2020-09-24 09:50:38
    C# 生成校验解析token方式1方式3转载自 https://www.cnblogs.com/fanfan-90/p/12911203.html 重要对象 JwtSecurityToken:代表一个jwt token,可以直接用此对象生成token字符串,也可以使用token字符串创建此对象 ...
  • import time import jwt # payload token_dict = { 'iat': time.time(), # 时间戳 'name': 'lowman' # 自定义的参数 } """payload 中一些固定参数名称的意义, 同时可以在payload中自定义参数"
  • Token验证失败的解决方法

    万次阅读 2016-11-11 15:12:47
    Token验证失败的解决方法
  • jmeter 实现token解析与认证

    千次阅读 2018-08-18 21:01:16
    jmeter 实现token解析与认证 jmeter版本:4.0 问题描述: 1、当前系统通过token实现系统安全验证,登录成功后,token被存储在返回体中(reaponse body),后续服务器请求时,需要将该token添加到请求头部...
  • } /** * 将token解析成实体类 * * @param token * @param clazz * @param * @return */ public static T get(String token, Class clazz) { if (StringUtils.isBlank(token)) { throw new RuntimeException("Token...
  • token的问题和原理解析

    千次阅读 2020-05-01 19:33:54
    1.token的原理和作用 ​ token是用于验证身份的,在web系统中验证前端是否能够访问后端系统 ​ token在服务端产生,如果前端使用用户名/密码向服务端请求认证,服务端认证成功,那么在服务端会返回 Token 给前端。...
  • 1、当前系统通过token实现系统安全验证,登录成功后,token被存储在返回体中(reaponse body),后续服务器请求时,需要将该token添加到请求头部(request header)中; 2、当前web服务访问时,强制限制必须适应谷歌...
  • 2019-02-19 碰到一个登录后从token取不到tokenId的问题,debug后没有发现什么异常; 2019-02-20 解决ing…
  • json解析错误

    万次阅读 2017-12-19 10:40:13
    用ajax请求,在后台查询出数据,放在json中组装成json数组,传回到前端,然后对data进行解析,但总是为空,alert出的数据也是json类型的,把alert出的数据粘到里面就可以解析成功
  • 1、当前系统通过token实现系统安全验证,登录成功后,token被存储在返回体中(reaponse body),后续服务器请求时,需要将该token添加到请求头部(request header)中; 2、当前web服务访问时,强制限制必须使用谷歌...
  • jwt认证机制实际上就是通过token密钥对于用户信息的认定 jwt工作原理(token运作流程) 从上图中可以看出,jwt的工作原理是:(以下号表示注释标号) (1)客户端通过post请求(1)将用户名密码提交给服务器,服务器验证...
  • security-oauth2(token解密过程)

    千次阅读 2020-11-10 13:48:19
    然后循环过滤器器链,利用过滤器链本身的匹配器对请求进行匹配,如果匹配通过,则进入到过滤器链中,然后循环执行过滤器链中所有的过滤器,在这些过滤器中,会对请求头信息中的token进行校验,如果全部校验通过,...
  • JWT能创建/解析token,一般由客户端上传手机号与验证码,服务器生成token,返回token给客户端,客户端使用此token访问其他需要登录的接口。 SpringBoot配置:...
  • JSON解析错误

    2020-04-27 14:16:16
    JMeter接口测试出现JSON解析出错的问题:"errorStackTrace":"JSON parse error: Unrecognized token 'robotCallJobId': was expecting ('true', 'false' or 'null'); 报错信息: {"code":500,"data":null,"request...
  • Unexpected token错误解析

    千次阅读 2018-12-28 09:51:23
    Unhandled Rejection (SyntaxError): Unexpected token < in JSON at position 0当你发送一个HTTP请求,可能是用Fetch或者其他的Ajax库,可能会出现这个错误提示,或者相似的错误。 接下来我将解释这是由什么引起...
  • React 登录获取token并存储及解析token

    万次阅读 2019-03-26 18:19:55
    仓库地址:... 目录 存储token 解析token 解决页面刷新,数据消失问题 当前目录: 存储token login.js import React, { Component } from 'react' // 实现ui组件和数据连接 i...
  • LoadRunner11 实现token解析与认证

    千次阅读 2018-08-18 20:06:46
    LoadRunner11 实现token解析与认证 需求描述: 1、当前系统通过token实现系统安全验证,登录成功后,token被存储在返回体中(reaponse body),后续服务器请求时,需要将该token添加到请求头部(request header)...
  • //异常信息解析 HttpOutputMessage outputMessage = newServletServerHttpResponse(response);try{//将exceptionResultInfo对象转成json输出,这里使用spring异常处理的工具 jsonMessageConverter.write...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 52,519
精华内容 21,007
关键字:

token解析错误