精华内容
下载资源
问答
  • token验证
    千次阅读
    2020-05-26 11:43:38

    为什么使用token验证

    在web领域基于token的身份验证随处可变,在大多说使用web API的互联网公司中,tokens是多用户下处理认证的最佳方式

    一下几点特性会让你在程序中使用基于Token 的身份验证

    • 无状态、可扩展
    • 支持移动设备
    • 跨程序调用
    • 安全

    那些使用基于Token的身份验证的大佬们

    大部分你见到过的API和WEB应用都是用tokens,列如facebook, twitter, google+, github等

    Token的起源

    在介绍基于token的身份验证的原理与优势之前,不妨先看看之前的认证都是怎么做的

    基于服务器的验证

    我们都是知道HTTP协议是无状态的,这种无状态意味着程序需要验证每一次请求,从而辨别客户端的身份。
    在这之前,程序都是通过在服务端存储的登录信息来辨别请求的。这种方式一般都是通过存储Session来完成。
    随着Web,应用程序,已经移动端的兴起,这种验证的方式逐渐暴露出了问题。尤其是在可扩展性方面。

    基于服务器的验证方式暴露的一些问题

    1、session:每次认证用户发起请求时, 服务器需要去创建一个记录来存储信息, 当越来越多的用户发请求时, 内存的开销也会不断增加

    2、可获振兴:在服务端的内存中使用session存储的登录信息,办所而来的是可扩展性问题

    3、CORS(跨域资源共享): 当我们需要让数据跨多台移动设备上使用时, 跨域资源共享回事一个让人头疼的问题, 在使用ajax抓取另一个域的资源,就可以会出现禁止请求的情况

    4、CSRF(跨站请求伪造): 用户在访问银行网站时, 他们很容易受到跨站请求伪造的攻击, 并且能够被利用其访问其他网站

    在这些问题中,可扩展性是最突出,因此我们有必要去寻求一种更有行之有效的方法

    基于TOKEN的验证原理

    基于Token的身份验证是无状态的,我们不将用户信息存在服务器或Session中。

    这种概念解决了在服务端存储信息时的许多问题

    NoSession意味着你的程序可以根据需要去增减机器,而不用去担心用户是否登录。

    基于Token的身份验证的过程如下:

    1.用户通过用户名和密码发送请求。

    2.程序验证。

    3.程序返回一个签名的token 给客户端。

    4.客户端储存token,并且每次用于每次发送请求。

    5.服务端验证token并返回数据。

    每一次请求都需要token。token应该在HTTP的头部发送从而保证了Http请求无状态。我们同样通过设置服务器属性Access-Control-Allow-Origin:* ,让服务器能接受到来自所有域的请求。需要主要的是,在ACAO头部标明(designating)*时,不得带有像HTTP认证,客户端SSL证书和cookies的证书。

    代码实例流程:
    
    //用户第一次登录
    username pwd client_type 
    //接口判断
    if(token&uid){
       查询token表
        $token=where uid =uid 
        if($token==token){
          登录成功!!
              返回token 和 uid
        }else{
          登录失败!!
        }
    }
    
    if(usename powd client_type){
         检验用户名和密码
        if(正确){
           得到uid 并 生成token(md5( uid.pwd.time() 自己定义规则 ))
            if(uid不存在){
                into token 表   id uid token
            }else{
                where uid=$uid 修改token
            }
            返回token 和 uid
        }else{
            返回错误信息;    
            }
    }
    
    客户端c进行文件存储uid 和token
    
    下次再次登录时使用uid和token
    

    实现了用户登录的互踢

    当我们在程序中认证了信息并取得token之后,我们便能通过这个Token做许多的事情。

    我们甚至能基于创建一个基于权限的token传给第三方应用程序,这些第三方程序能够获取到我们的数据(当然只有在我们允许的特定的token)

    Tokens的优势

    无状态、可扩展

    在客户端存储的Tokens是无状态的,并且能够被扩展。基于这种无状态和不存储Session信息,负载负载均衡器能够将用户信息从一个服务传到其他服务器上。

    如果我们将已验证的用户的信息保存在Session中,则每次请求都需要用户向已验证的服务器发送验证信息(称为Session亲和性)。用户量大时,可能会造成

    一些拥堵。

    但是不要着急。使用tokens之后这些问题都迎刃而解,因为tokens自己hold住了用户的验证信息。

    安全性

    请求中发送token而不再是发送cookie能够防止CSRF(跨站请求伪造)。即使在客户端使用cookie存储token,cookie也仅仅是一个存储机制而不是用于认证。不将信息存储在Session中,让我们少了对session操作。

    token是有时效的,一段时间之后用户需要重新验证。我们也不一定需要等到token自动失效,token有撤回的操作,通过token revocataion可以使一个特定的token或是一组有相同认证的token无效。

    可扩展性()

    Tokens能够创建与其它程序共享权限的程序。例如,能将一个随便的社交帐号和自己的大号(Fackbook或是Twitter)联系起来。当通过服务登录Twitter(我们将这个过程Buffer)时,我们可以将这些Buffer附到Twitter的数据流上(we are allowing Buffer to post to our Twitter stream)。

    使用tokens时,可以提供可选的权限给第三方应用程序。当用户想让另一个应用程序访问它们的数据,我们可以通过建立自己的API,得出特殊权限的tokens。

    多平台跨域

    我们提前先来谈论一下CORS(跨域资源共享),对应用程序和服务进行扩展的时候,需要介入各种各种的设备和应用程序。

    Having our API just serve data, we can also make the design choice to serve assets from a CDN. This eliminates the issues that CORS brings up after we set a quick header configuration for our application.

    只要用户有一个通过了验证的token,数据和资源就能够在任何域上被请求到。

    <span style="margin:0px; padding:0px; color:rgb(255,255,255); background-color:rgb(0,0,0)"><code class=" language-javascript" style="margin:0px; padding:0px">          Access<span class="token operator" style="margin:0px; padding:0px">-Control<span class="token operator" style="margin:0px; padding:0px">-Allow<span class="token operator" style="margin:0px; padding:0px">-Origin<span class="token punctuation" style="margin:0px; padding:0px">: <span class="token operator" style="margin:0px; padding:0px">*       <br style="margin:0px; padding:0px" /></span></span></span></span></span></code></span>
    
    

    基于标准

    创建token的时候,你可以设定一些选项。我们在后续的文章中会进行更加详尽的描述,但是标准的用法会在JSON Web Tokens体现。

    最近的程序和文档是供给JSON Web Tokens的。它支持众多的语言。这意味在未来的使用中你可以真正的转换你的认证机制。

    总结

    这篇文章仅仅是介绍了为什么选择基于Token的身份验证,并且怎样使用它。

    更多相关内容
  • 今天小编就为大家分享一篇python 产生token及token验证的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
  • 在使用URL和Token启用微信公众平台开发模式消息接口的时候,我们会碰到三种情况,token验证失败,请求url超时,提交成功
  • Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).这篇文章主要介绍了SpringBoot集成JWT实现token验证,需要的朋友可以参考下
  • Token验证是验证用户身份的重要方式,在golang开发中具有广泛应用,文中主要阐述了利用jwt包加密后的token验证。 导入包: import ( "github.com/dgrijalva/jwt-go" ) // GenerateToken 生成Token func ...
  • C#WEB用户令牌TOKEN验证,防止HTTP、GET、POST等提交包含服务端和客户端源码。Nginx集群,SSL证书的WebApi令牌验证
  • 主要介绍了jQury Ajax使用Token验证身份实例代码,需要的朋友可以参考下
  • 主要介绍了基于vue 实现token验证的实例代码,非常不错,具有参考借鉴价值,需要的朋友可以参考下
  • 在vue单页中,我们可以通过监控route对象,从中匹配信息去决定是否验证token,然后定义后续行为。下面通过实例代码给大家分享vue登录注册及token验证功能,需要的朋友参考下吧
  • Token验证的代码

    2017-09-08 10:47:52
    基于spring框架,数据交互是依据URLConnection进行数据传递的,参数在传递的过程使用RAS进行数据加密和MD5加密。
  • 主要介绍了Spring Cloud Gateway使用Token验证详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • 主要为大家详细介绍了基于redis实现token验证用户是否登陆,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • JAVA微信公众平台Token验证

    热门讨论 2014-12-08 11:34:48
    首先要开启开发模式必须要进行Token的一个验证,你给出一个地址,微信发送请求,然后你给出相应,就这么简单。虽然说是简单,但是这是事后才说的,官方只有PHP的DEMO,我用JAVA开发的时候各种蛋疼不会弄,不过好在...
  • 主要介绍了PHP token验证生成原理,结合实例形式分析了php的token验证原理与使用技巧,需要的朋友可以参考下
  • 后端不再存储认证信息,而是在用户登录的时候生成一个token,然后返回给前端,前端进行存储,在需要进行验证的时候将token一并发送到后端,后端进行验证 加密的方式:对称加密和非对称加密,对称加密指的是加密解密...
  • token验证的方法

    千次阅读 2022-03-20 19:48:56
    token校验、token验证、注解校验tokentoken的获取、远程解析token、解析token、分布式系统验证token

    统一token处理

    自定义注解的方法及使用

    排除token校验注解类

    为不需要校验 token 的方法定义注解
    @Documented //标记注解
    @Target(ElementType.METHOD) //指定作用在方法上 对方法拦截
    @Retention(RetentionPolicy.RUNTIME) //作用域 在运行时有效

    NoAuthorization.java

    import java.lang.annotation.*;
    
    /**
     * 包含该注解的方法 不需要校验token  直接放行
     * @author 陌路
     * @date 2022-03-19
     * @apiNote token统一处理
     */
    @Documented//标记注解
    @Target(ElementType.METHOD) //指定作用在方法上 对方法拦截
    @Retention(RetentionPolicy.RUNTIME) //作用域 在运行时有效
    public @interface NoAuthorization {
    
        /** ---------@定义注解---------
         *  元注解
         *    @Target({METHOD,TYPE}) 表示这个注解可以用用在类/接口上,还可以用在方法上
         *    @Retention(RetentionPolicy.RUNTIME) 表示这是一个运行时注解,即运行起来之后,
         *	  才获取注解中的相关信息,而不像基本注解如@Override 那种。
         *    @Inherited 表示这个注解可以被子类继承
         *    @Documented 表示当执行javadoc的时候,本注解会生成相关文档(标记)
         *
         *  自定义注解的使用:
         *  该注解定义好之后,将该注解加在方法上@NoAuthorization即可,
         *  若注解中存在属性需要赋值,则直接可以在注解中赋值即可,
         *	eg:public @interface ZjObj{
         *		String name();
         *		Integer sex();
         *	}
         *  eg: @ZjObj(属性="值") -> @ZjObj(name="张三",sex=1)
         *
         *  也可这样定义注解,效果都是一样的
         *  @Target(value = { ElementType.ANNOTATION_TYPE })
         *  @Retention(RetentionPolicy.RUNTIME)
         *  @Inherited
         *  @Documented
         *
         * ---------@解析注解@使用注解---------
         *  * 若注解中有属性,则可以直接通过反射来获取属性值
         *  * 相关配置信息本来是以属性的方式存放的,现在改为了以注解的方式
         *  *
         *  * @解析注解: 通过反射,获取这个类上的注解对象
         *  * ZjObj zjObj = class.foraName(ZjObj.class);
         *  * 拿到注解对象之后,通过方法,获取各个注解元素的值:
         *  * String name = zjObj.name();
         *  * Integer sex = zjObj.sex ();
         */
    }
    

    本地线程缓存类

    封装获取当前登录人数据信息类

    TokenInterceptor 将获取到的user数据信息添加到 本地线程UserThreadLocal中去
    TokenInterceptor类中实现了HandlerInterceptor拦截器,对请求进行了拦截
    并对token进行了校验,token有效就会把user数据信息存储到UserThreadLocal当前类中
    通过调用该类的get()方法时,即可获取到user的数据信息

    UserThreadLocal.java

    /**
     * 获取当前登录人信息
     * @author 陌路
     * @date 2022-03-19
     * @apiNote 封装当前登录用户信息
     */
    public class UserThreadLocal {
        private static final ThreadLocal<User> LOCAL = new ThreadLocal<User>();
        /**
         * `TokenInterceptor`类中实现了`HandlerInterceptor`拦截器,对请求进行了拦截
         * 并对token进行了校验,token有效就会把`user`数据信息存储到当前类中
         * 通过调用该类的`get()`方法时,即可获取到`user`的数据信息
         */
    
        //构造方法私有化,不运行外部实例化该对象
        private UserThreadLocal() {
        }
        public static void set(User user) {
            LOCAL.set(user);
        }
        public static User get() {
            return LOCAL.get();
        }
    }
    

    token校验类

    定义方法的请求拦截器,判断用户请求的方法是否需要校验token信息,preHandle 前置拦截

    此拦截器是在执行用户请求的方法前拦截到的,该拦截器结束之前,不会执行用户请求的方法

    当该拦截器执行完成后,根据拦截器返回结果(true|false)判断是否继续执行用户的请求

    preHandle 返回 false 时,用户请求将不再继续执行,为 true 时校验通过才会继续执行


    思路:
    首先判断用户请求的方法中是否包含了@NoAuthorization注解 若包含了该注解 则放行
    如果不包含该注解,说明需要对token进行校验,继续执行下面的校验代码
    校验:首先判断请求头中是否包含 "Authorization"请求头数据 不包含则结束校验 不予访问
    若包含,则需要解析token数据拿到user对象,不为空就把当前user对象存储到UserThreadLocal线程中去并返回true验证成功

    TokenInterceptor.java

    import org.apache.commons.lang3.StringUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    import org.springframework.web.method.HandlerMethod;
    import org.springframework.web.servlet.HandlerInterceptor;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    /**
     * 请求拦截器 统一token校验
     * @author 陌路
     * @date 2022-03-19
     * @apiNote 统一token校验
     */
    @Component
    public class TokenInterceptor implements HandlerInterceptor {
    
        @Autowired
        private UserService userService;
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
            /** 思路
             * 首先判断请求的方法中是否包含了@NoAuthorization注解 若包含了此注解 则不作处理
             * 包含该@NoAuthorization注解 表示不需要做token的验证 直接return true 放行即可
             * 如果不包含该注解,说明需要对token进行校验,则继续执行下面的代码
             * 校验:首先判断请求头中是否包含 "Authorization" 请求头数据 不包含则结束校验 不予访问
             * 若包含 则需要解析token数据 拿到 user 对象,判断user对象是否为null
             * 为null 说明不存在,直接返回false,不予访问,重新登录
             * 不为空 则需要把当前user对象存储到 UserThreadLocal 线程中去 并返回true 验证成功
             */
            // 如果 handler 是 HandlerMethod 类型,则把 handler(Object类型)转为HandlerMethod类型
            if (handler instanceof HandlerMethod) {
                HandlerMethod handlerMethod = (HandlerMethod) handler;
                // 获取将要访问的方法名,根据方法名获取方法上的 NoAuthorization 注解,判断该注解是否存在
                NoAuthorization noAuthorization = handlerMethod
                    			.getMethod()
                    			.getAnnotation(NoAuthorization.class);
                //若方法中存在该 NoAuthorization 注解,则表示无需校验 返回true
                if (noAuthorization != null) {
                    return true;
                }
            }
            //获取到请求头中的头信息(token)
            String token = request.getHeader("Authorization");
            //判断token是否存在
            if (StringUtils.isNotEmpty(token)) {
                //存在则根据token解析user数据
                User user = this.userService.queryUserByToken(token);
                //判断解析的user数据是否为null
                if (null != user) {
                    //不为空 则将user信息存储到线程中
                    UserThreadLocal.set(user);
                    return true;
                }
            }
            //若请求头中不存在Authorization 直接返回false 提示状态码401无权限
            response.setStatus(401);
            return false;
        }
    }
    

    Service解析token实现类

    解析token数据,把token数据解析为user对象

    解析完成后重置缓存时长,将缓存时间重新增加到一个小时

    /**
      * 解析token,获取user数据信息
      * 对token进行检测,如果token存在,则解析出user数据信息
      * 如果token不存在,则return null
      * 除注册和发送验证码外不需要检测token外,其他功能均需要检测token
      */
    @Override
    public User queryUserByToken(String token) {
        try {
            // 生成redisKey获取当前登陆人信息
            String redisTokenKey = "TOKEN_" + token;
            // 获取缓存数据
            String cacheData = this.redisTemplate.opsForValue().get(redisTokenKey);
            if (StringUtils.isNotEmpty(cacheData)) {
                // 刷新时间
                this.redisTemplate.expire(redisTokenKey, 1, TimeUnit.HOURS);
                //反序列化,将JSON数据转化为user对象返回
                return MAPPER.readValue(cacheData, User.class);
            }    
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    

    如果是分布式系统,需要远程调用SSO服务验证token的,可以加上下面的代码

    编码格式和超时时间配置类(远程调用支持类)

    配置 RestTemplate 模板,设置服务远程调用过程中的编码格式

    添加消息数据的字符集格式、连接超时时间和数据获取超时时间

    RestTemplateConfig.java

    /**
     * RestTemplate模板配置类
     * @author 陌路
     * @date 2022-03-19
     * @apiNote 设置模板的字符集、链接超时时间和获取超时时间
     */
    @Configuration
    public class RestTemplateConfig {
    
        @Bean
        public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
            RestTemplate restTemplate = new RestTemplate(factory);
            // 支持中文编码,getMessageConverters消息转换器,将字符集设置为 UTF-8
            restTemplate.getMessageConverters()
                .set(1, new StringHttpMessageConverter(Charset.forName("UTF-8")));
            return restTemplate;
        }
    
        @Bean
        public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
            SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
            // 设置数据获取的超时时间,单位为ms
            factory.setReadTimeout(5000);
            // 设置连接超时时间,单位为ms
            factory.setConnectTimeout(5000);
            return factory;
        }
    }
    

    远程调用Service类

    远程服务调用,验证和获取token数据(调用SSO单点登录中接口)

    url:url为SSO单点登录服务器的IP地址和端口加协议的全名地址

    eg:http://47.101.xxx.xxx:80 本地:eg:http://127.0.0.1:80

    该方法涉及了服务的远程调用过程,需要使用 RestTemplate 中的 .getForObject();

    把上面的service解析token的方法改为下面这段代码

    /**
      * 解析Token
      * 调用SSO接口进行解析token
      * @param token
      * @return
      */
    public User queryUserByToken(String token) {
        try {
            // 返回一串JSON字符串,url为SSO单点登录服务器的ip地址和端口eg:http://127.0.0.1:80
            String url = "http://192.168.10.188:18080";
            String jsonData = this.restTemplate.getForObject(url + "/user/{token}", String.class, token);
            // 如果查询到就返回user对象 查询不到就返回null
            if (StringUtils.isNotEmpty(jsonData)) {
                // MAPPER.readValue方法将JSON字符串转化为对象 并返回
                return MAPPER.readValue(jsonData, User.class);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    

    controller控制器接口

    远程服务调用,被调用的接口(SSO单点登录中的控制器接口)

    远程服务调用此接口需要使用全名地址:
    协议://ip地址:端口号 http://ip:port (https://ip:port)

    下面的controller作为SSO中被远程调用的测试接口(请根据实际接口调用)
    /**
      * 验证token
      * @param token
      * @return
      */
    @GetMapping("{token}")
    public User queryUserByToken(@PathVariable("token") String token) {
        //根据token把查询到的结果返回
        return this.userService.queryUserByToken(token);
    }
    

    自定义注解的方法及使用:https://blog.csdn.net/qq_51076413/article/details/123620875

    展开全文
  • PHP如何实现Token验证

    千次阅读 2021-03-24 09:37:20
    PHP如何实现Token验证首先将Token进行解析;然后根据解析出来的信息部分验证是否过期,如果未过期再将解析出的信息部分进行加密;最后将加密出来的数据和解析出来签名进行比对,如果相同则验证成功。示例代码:...

    899210456b5abfce56e6e8f03f4ee9f2.png

    PHP如何实现Token验证

    首先将Token进行解析;然后根据解析出来的信息部分验证是否过期,如果未过期再将解析出的信息部分进行加密;最后将加密出来的数据和解析出来签名进行比对,如果相同则验证成功。

    示例代码:<?php

    function check_token($token) {

    /**** api传来的token ****/

    if(!isset($token) || empty($token)) {

    $msg['code']='400';

    $msg['msg']='非法请求';

    return json_encode($msg,JSON_UNESCAPED_UNICODE);

    }

    //对比token

    $explode = explode('.',$token);

    //以.分割token为数组

    if(!empty($explode[0]) && !empty($explode[1]) && !empty($explode[2]) && !empty($explode[3]) ) {

    $info = $explode[0].'.'.$explode[1].'.'.$explode[2];

    //信息部分

    $true_signature = hash_hmac('md5',$info,'siasqr');

    //正确的签名

    if(time() > $explode[2]) {

    $msg['code']='401';

    $msg['msg']='Token已过期,请重新登录';

    return json_encode($msg,JSON_UNESCAPED_UNICODE);

    }

    if ($true_signature == $explode[3]) {

    $msg['code']='200';

    $msg['msg']='Token合法';

    return json_encode($msg,JSON_UNESCAPED_UNICODE);

    } else {

    $msg['code']='400';

    $msg['msg']='Token不合法';

    return json_encode($msg,JSON_UNESCAPED_UNICODE);

    }

    } else {

    $msg['code']='400';

    $msg['msg']='Token不合法';

    return json_encode($msg,JSON_UNESCAPED_UNICODE);

    }

    }

    推荐教程:《PHP教程》

    展开全文
  • Json web token (JWT),是为了在网络应用环境间传递声明而执行的一种基于 JSON 的开放标准((RFC 7519),该 token 被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT 的声明一般被用来在身份...

    什么是JWT?

    Json web token (JWT),是为了在网络应用环境间传递声明而执行的一种基于 JSON 的开放标准((RFC 7519),该 token 被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT 的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。

    为什么需要JWT?

    当我们开发前后端分离项目时,要求我们对用户会话状态要进行一个无状态处理,那我们知道普通的web项目用于管理用户会话的往往是 session,用户每次用服务器认证成功后,服务器都会发送一个 sessionid 给用户,session 是保存在服务端的,服务器通过 session 分辨用户,进行权限认证等一系列操作。每次请求完后,都会在 响应头中返回 sessionid 给浏览器,浏览器会将 sessionid 存储在 cookie 中,以后的每次请求都会在请求头中带上这个 sessionid 信息,服务器就会根据这个 sessionid 作为索引获取到具体的 session。

    那上面讲述的场景就会出现一个痛点,当我们前后端分离后,我们的前端项目和后端项目分开部署,甚至会用到 nginx 来代理转发,也就是说前后端分离在应用解耦后增加了部署的复杂性。通常用户一次请求就要转发多次。如果用 session 每次携带 sessionid 到服务器,服务器还要查询用户信息。同时如果用户很多。这些信息存储在服务器内存中,给服务器增加负担。还有就是 CSRF(跨站伪造请求攻击)攻击,session 是基于 cookie 进行用户识别的, cookie 如果被截获,用户就会很容易受到跨站请求伪造的攻击。还有就是 sessionid 就是一个特征值,表达的信息不够丰富。不容易扩展。而且如果你后端应用是多节点部署。那么就需要实现 session 共享机制。不方便集群应用。

    JWT的应用场景

    JWT 就是上述痛点的解决方案之一,客户端在请求服务端进行登录操作时,服务端验证用户的账号和密码,验证成功后生成 token 返回给客户端,之后浏览器的每一次操作都会在请求头中带上这个 token,服务器会验证该 token 信息,验证成功后才会返回资源给浏览器。

    JWT 的开销非常小,可以轻松在不同的域名中传递,所以在单点登录(SSO)中用到比较广泛,信息交换在通信的双方之间使用JWT对数据进行编码是一种非常安全的方式,由于它的信息是经过签名的,可以确保发送者发送的信息是没有经过伪造的。

    整合JWT

    1、引入 JWT 依赖

    <!-- 引入jwt -->
    <dependency>
        <groupId>com.auth0</groupId>
        <artifactId>java-jwt</artifactId>
        <version>3.8.2</version>
    </dependency>
    

    2、JWT 工具类

    • 工具类中包含:创建 token,验证 token,获取用户 id 等
    package com.asurplus.common.jwt;
    
    import cn.hutool.core.collection.CollectionUtil;
    import com.asurplus.common.utils.ResponseResult;
    import com.asurplus.common.utils.SpringContextUtils;
    import com.auth0.jwt.JWT;
    import com.auth0.jwt.algorithms.Algorithm;
    import com.auth0.jwt.exceptions.JWTVerificationException;
    import com.auth0.jwt.interfaces.DecodedJWT;
    import com.auth0.jwt.interfaces.JWTVerifier;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.commons.lang3.StringUtils;
    
    import javax.servlet.http.HttpServletRequest;
    import java.util.Date;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    /**
     * Jwt工具类,生成JWT和认证
     *
     * @author dongk
     * @date 2021-02-05 11:10:08
     */
    @Slf4j
    public class JwtUtil {
    
        /**
         * 密钥
         */
        private static final String SECRET = "asurplus_secret";
    
        /**
         * 过期时间(单位:秒)
         **/
        private static final long EXPIRATION = 3600L;
    
        /**
         * 生成用户token,设置token超时时间
         *
         * @param userId
         * @param password
         * @return
         */
        public static String createToken(Integer userId, String account, String password) {
            Map<String, Object> map = new HashMap<>();
            map.put("alg", "HS256");
            map.put("typ", "JWT");
            String token = JWT.create()
                    // 添加头部
                    .withHeader(map)
                    // 放入用户的id
                    .withAudience(String.valueOf(userId))
                    // 可以将基本信息放到claims中
                    .withClaim("account", account)
                    .withClaim("password", password)
                    // 超时设置,设置过期的日期
                    .withExpiresAt(new Date(System.currentTimeMillis() + EXPIRATION * 1000))
                    // 签发时间
                    .withIssuedAt(new Date())
                    // SECRET加密
                    .sign(Algorithm.HMAC256(SECRET));
            return token;
        }
    
        /**
         * 获取用户id
         */
        public static Integer getUserId() {
            HttpServletRequest request = SpringContextUtils.getHttpServletRequest();
            // 从请求头部中获取token信息
            String token = request.getHeader("Authorization");
            if (StringUtils.isBlank(token)) {
                return null;
            }
            try {
                Algorithm algorithm = Algorithm.HMAC256(SECRET);
                JWTVerifier verifier = JWT.require(algorithm).build();
                DecodedJWT jwt = verifier.verify(token);
                if (null != jwt) {
                    // 拿到我们放置在token中的信息
                    List<String> audience = jwt.getAudience();
                    if (CollectionUtil.isNotEmpty(audience)) {
                        return Integer.parseInt(audience.get(0));
                    }
                }
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (JWTVerificationException e) {
                e.printStackTrace();
            }
            return null;
        }
    
        /**
         * 校验token并解析token
         */
        public static ResponseResult verity() {
            HttpServletRequest request = SpringContextUtils.getHttpServletRequest();
            // 从请求头部中获取token信息
            String token = request.getHeader("Authorization");
            if (StringUtils.isBlank(token)) {
                return ResponseResult.error(401, "用户信息已过期,请重新登录");
            }
            try {
                Algorithm algorithm = Algorithm.HMAC256(SECRET);
                JWTVerifier verifier = JWT.require(algorithm).build();
                DecodedJWT jwt = verifier.verify(token);
                if (null != jwt) {
                    // 拿到我们放置在token中的信息
                    List<String> audience = jwt.getAudience();
                    if (CollectionUtil.isNotEmpty(audience)) {
                        return ResponseResult.success("认证成功", audience.get(0));
                    }
                }
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (JWTVerificationException e) {
                e.printStackTrace();
            }
            return ResponseResult.error(401, "用户信息已过期,请重新登录");
        }
    }
    
    

    我们可以看出 token 的创建用到了如下参数:

    • 算法:HS256
    • 类型:jwt
    • withAudience:向有效负载添加特定的受众(“aud”)声明,我们可以在这里放入一些用户的信息,例如:用户 id
    • withClaim:添加自定义索赔值,我们使用用户的账户和密码进行一起加密生成 jwt
    • withExpiresAt:超时时间设置,超时 token 将失效
    • withIssuedAt:签发时间,一般设置为当前时间
    • sign:签名,我们可以自定义签名和算法

    JWT 的验证:

    • 首先我们先要获取 HttpServletRequest 请求对象,工具类放在下面了
    • 从请求头中获取 token 信息,根据 key(Authorization)获取 value 值
    • 然后使用签名进行算法加密得到 jwt 的验证对象,JWTVerifier.verify(token) 用来验证 token 的正确性
    • 我们还可以从验证得到的 DecodedJWT 对象中获取我们创建 token 的时候放入的信息,例如:用户 id

    获取 HttpServletRequest 对象工具类

    package com.asurplus.common.utils;
    
    import org.springframework.beans.BeansException;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    import org.springframework.stereotype.Component;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;
    
    import javax.servlet.http.HttpServletRequest;
    
    /**
     * SpringContext工具类
     *
     * @Author Lizhou
     */
    @Component
    public class SpringContextUtils implements ApplicationContextAware {
    
        /**
         * 上下文对象实例
         */
        private static ApplicationContext applicationContext;
    
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            SpringContextUtils.applicationContext = applicationContext;
        }
    
        /**
         * 获取applicationContext
         *
         * @return
         */
        public static ApplicationContext getApplicationContext() {
            return applicationContext;
        }
    
        /**
         * 获取HttpServletRequest
         */
        public static HttpServletRequest getHttpServletRequest() {
            return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        }
    
        public static String getDomain() {
            HttpServletRequest request = getHttpServletRequest();
            StringBuffer url = request.getRequestURL();
            return url.delete(url.length() - request.getRequestURI().length(), url.length()).toString();
        }
    
        public static String getOrigin() {
            HttpServletRequest request = getHttpServletRequest();
            return request.getHeader("Origin");
        }
    }
    

    自定义 JSON 对象工具类

    package com.asurplus.common.utils;
    
    import com.asurplus.common.enums.BaseEnums;
    import com.asurplus.common.enums.StatusEnums;
    import io.swagger.annotations.ApiModelProperty;
    import lombok.Data;
    
    import java.io.Serializable;
    
    /**
     * 单例模式返回接口相应数据
     *
     * @Author Lizhou
     */
    @Data
    public class ResponseResult implements Serializable {
    
        @ApiModelProperty(value = "状态码")
        private Integer code;
    
        @ApiModelProperty(value = "提示信息")
        private String msg;
    
        @ApiModelProperty(value = "返回数据")
        private Object data;
    
        private static ResponseResult resultData(Integer code, String msg, Object data) {
            ResponseResult res = new ResponseResult();
            res.setCode(code);
            res.setMsg(msg);
            res.setData(data);
            return res;
        }
    
        /**
         * 成功
         */
        public static ResponseResult success() {
            return resultData(200, "操作成功", null);
        }
    
        /**
         * 成功
         */
        public static ResponseResult success(String msg) {
            return resultData(200, msg, null);
        }
    
        /**
         * 成功
         */
        public static ResponseResult success(Object data) {
            return resultData(200, "操作成功", data);
        }
    
        /**
         * 成功
         */
        public static ResponseResult success(String msg, Object data) {
            return resultData(200, msg, data);
        }
    
        /**
         * 失败
         */
        public static ResponseResult error() {
            return resultData(500, "操作失败", null);
        }
    
        /**
         * 失败
         */
        public static ResponseResult error(Integer code) {
            return resultData(code, null, null);
        }
    
        /**
         * 失败
         */
        public static ResponseResult error(Integer code, String msg) {
            return resultData(code, msg, null);
        }
    
        /**
         * 失败
         */
        public static ResponseResult error(String msg) {
            return resultData(500, msg, null);
        }
    
        /**
         * 失败
         */
        public static ResponseResult error(Object data) {
            return resultData(500, "操作失败", data);
        }
    
        /**
         * 失败
         */
        public static ResponseResult error(Integer code, String msg, Object data) {
            return resultData(code, msg, data);
        }
    
        /**
         * 失败
         */
        public static ResponseResult error(BaseEnums enums) {
            return resultData(enums.getCode(), enums.getMsg(), null);
        }
    }
    

    至此,我们在 SpringBoot 中整合 JWT 实现 Token 验证已经完成。

    如您在阅读中发现不足,欢迎留言!!!

    展开全文
  • 令牌概述(Token) 在以用户账号体系作为安全认证的信息系统中,对用户身份的鉴定是非常重要的事情。 令牌机制是软件系统安全体系中非常重要的部分,在计算机身份认证中是令牌的意思,一般作为邀请、登录...
  • token验证概述及在React中实现token验证1 什么是token2 token的作用3 React中实现token验证 1 什么是token token的意思是“令牌”,是服务端生成的一串字符串,作为客户端进行请求的一个标识。当用户第一次登录后,...
  • nginx+lua+redis实现token验证。实现基本的token验证、反向代理转发内部服务,lua连接redis封装、lua域名解析封装、lua域名脚本等
  • Java用户登录之token验证

    千次阅读 2021-02-12 09:10:18
    1.场景还原可能还有很多小伙伴对token概念朦朦胧胧,今天笔者以项目中的用户登录的token验证需求跟大家讲讲其中的来龙去脉,希望能够理清大伙的思路。2.需求分析这个需求可能早已是老生常谈,但我觉得它永远也不会...
  • Android/IOS基于token验证服务器端实现,含源码,包括filter 过滤验证token,验证token,账号互踢,根据token获取个人信息到request,controller中如何获取个人信息。
  • Token验证实现思路

    2021-09-01 21:24:58
    Token 是一个临时、唯一、保证不重复的令牌 Token的引入:Token是在客户端频繁向服务端请求数据,服务端频繁的去数据库查询用户名和密码并进行对比,判断用户名和密码正确与否,并作出相应提示,在这样的背景下,...
  • 如果对整合 JWT 还不熟悉的朋友,可以先看看我的这篇博客:【SpringBoot】四十四、SpringBoot中整合JWT实现Token验证 自定义注解 1、创建自定义注解 package com.asurplus.common.annotation; import
  • nginx进行token验证

    千次阅读 2020-03-25 16:33:58
    最近在做图片服务的时候,一开始用的tomcat,图片的url后面拼接上token,在tomcat里进行token验证后再把二进制流返回给前台。不过,我们项目中有一个页面,在进去的时候,会一次性加载1000张左右的图片,等图片加载完,花都...
  • Token验证详解

    万次阅读 2018-06-21 14:13:10
    注:解释的也是非常清晰,很受用一篇文章。...为什么使用Token验证: &nbsp; 在Web领域基于Token的身份验证随处可见。在大多数使用Web API的互联网公司中,tokens 是多用户下处理认证的最佳方式。 &nbsp; 以...
  • tp6使用token验证

    2021-10-28 15:16:53
    function_exists('signToken')) { //生成验签 function signToken($uid){ $key='!@#$%*&'; //这里是自定义的一个随机字串,应该写在config文件中的,解密时也会用,相当 于加密中常用的 盐 salt $token=...
  • Golang jwt-go 实现token验证身份

    千次阅读 2020-12-29 11:08:07
    本文只说明如何从HTTP请求中解析tokentoken验证是一种web常用的身份验证手段,在这里不讨论它的具体实现我需要在golang里实现token验证,Web框架是Gin(当然这与框架没有关系)步骤如下从request获取tokenstring将...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 198,056
精华内容 79,222
关键字:

token验证

友情链接: 全息.rar