Token登陆验证机制的原理及实现

session简介

做过Web开发的程序员应该对Session都比较熟悉,Session是一块保存在服务器端的内存空间,一般用于保存用户的会话信息。

用户通过用户名和密码登陆成功之后,服务器端程序会在服务器端开辟一块Session内存空间并将用户的信息存入这块空间,同时服务器会在cookie中写入一个Session_id的值,这个值用于标识这个内存空间。

下次用户再来访问的话会带着这个cookie中的session_id,服务器拿着这个id去寻找对应的session,如果session中已经有了这个用户的登陆信息,则说明用户已经登陆过了。

使用Session保持会话信息使用起来非常简单,技术也非常成熟。但是也存在下面的几个问题:

  • 服务器压力大:通常Session是存储在内存中的,每个用户通过认证之后都会将session数据保存在服务器的内存中,而当用户量增大时,服务器的压力增大。
  • Session共享:现在很多应用都是分布式集群,需要我们做额外的操作进行Session共享;
  • CSRF跨站伪造请求攻击:Session机制是基于浏览器端的cookie的,cookie如果被截获,用户就会很容易受到跨站请求伪造的攻击。

基于token的认证

基于token的认证机制将认证信息返回给客户端并存储。下次访问其他页面,需要从客户端传递认证信息回服务端。简单的流程如下:

  • 客户端使用用户名跟密码请求登录;
  • 服务端收到请求,去验证用户名与密码;
  • 验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端;
  • 客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者 Local Storage 里;
  • 客户端每次向服务端请求资源的时候需要带着服务端签发的 Token;
  • 服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据;

基于token的验证机制,有以下的优点:

  • 支持跨域访问,将token置于请求头中,而cookie是不支持跨域访问的;
  • 无状态化,服务端无需存储token,只需要验证token信息是否正确即可,而session需要在服务端存储,一般是通过cookie中的sessionID在服务端查找对应的session;
  • 无需绑定到一个特殊的身份验证方案(传统的用户名密码登陆),只需要生成的token是符合我们预期设定的即可;
  • 更适用于移动端(Android,iOS,小程序等等),像这种原生平台不支持cookie,比如说微信小程序,每一次请求都是一次会话,当然我们可以每次去手动为他添加cookie,详情请查看博主另一篇博客;
  • 避免CSRF跨站伪造攻击,还是因为不依赖cookie;

缺点的话一个就是相比较于传统的session登陆机制实现起来略微复杂一点,另外一个比较大的缺点是由于服务器不保存 token,因此无法在使用过程中废止某个 token,或者更改 token 的权限。也就是说,一旦 token 签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑。

退出登陆的话,只要前端清除token信息即可。

基于JWT的token认证实现

JWT(JSON Web Token)就是基于token认证的代表,这边就用JWT为列来介绍基于token的认证机制。

需要引入JWT的依赖

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

生成token和验证token的工具类如下:

public class JWTTokenUtil {
    //设置过期时间
    private static final long EXPIRE_DATE=30*60*100000;
    //token秘钥
    private static final String TOKEN_SECRET = "ZCfasfhuaUUHufguGuwu2020BQWE";

    public static String token (String username,String password){

        String token = "";
        try {
            //过期时间
            Date date = new Date(System.currentTimeMillis()+EXPIRE_DATE);
            //秘钥及加密算法
            Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
            //设置头部信息
            Map<String,Object> header = new HashMap<>();
            header.put("typ","JWT");
            header.put("alg","HS256");
            //携带username,password信息,生成签名
            token = JWT.create()
                    .withHeader(header)
                    .withClaim("username",username)
                    .withClaim("password",password).withExpiresAt(date)
                    .sign(algorithm);
        }catch (Exception e){
            e.printStackTrace();
            return  null;
        }
        return token;
    }

    public static boolean verify(String token){
        /**
         * @desc   验证token,通过返回true
         * @params [token]需要校验的串
         **/
        try {
            Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
            JWTVerifier verifier = JWT.require(algorithm).build();
            DecodedJWT jwt = verifier.verify(token);
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return  false;
        }
    }
    public static void main(String[] args) {
        String username ="name1";
        String password = "pw1";
        //注意,一般不会把密码等私密信息放在payload中,这边只是举个列子
        String token = token(username,password);
        System.out.println(token);
        boolean b = verify(token);
        System.out.println(b);
    }
}

执行结果如下:

Connected to the target VM, address: '127.0.0.1:11838', transport: 'socket'
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwYXNzd29yZCI6IjEyMyIsImV4cCI6MTU5NzM5Nzc0OCwidXNlcm5hbWUiOiJ6aGFuZ3NhbiJ9.LI5S_nX-YcqtExI9UtKiP8FPqpQW_ccaws2coLzyOS0
true

关于DecodedJWT这个类,大家可以重点看下,里面包含了解码后的用户信息。

JWT的使用说明

客户端收到服务器返回的 JWT,可以储存在 Cookie 里面,也可以储存在 localStorage。

此后,客户端每次与服务器通信,都要带上这个 JWT。你可以把它放在 Cookie 里面自动发送,但是这样不能跨域,所以更好的做法是放在 HTTP 请求的头信息Authorization字段里面。

Authorization: Bearer <token>

另一种做法是,跨域的时候,JWT 就放在 POST 请求的数据体里面。

JWT 本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT 的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证。

为了减少盗用,JWT 不应该使用 HTTP 协议明码传输,要使用 HTTPS 协议传输。(或者是对JWT在前后端之间进行加密之后在传输)

关于JWT的一个问题

上面生成JWT token的过程关键点就是密钥,假如这个密钥泄露了,那是不是就可以伪造token了。

还有就是生产环境的密钥值,开发的程序员大概率是知道的,怎么防止程序要监守自盗,伪造token值呢?希望有经验的大佬指教下。

//token秘钥
private static final String TOKEN_SECRET = "ZCfasfhuaUUHufguGuwu2020BQWE";

关于上面的问题,@仙湖码农 给出了一个简单易懂的方案~

jwt 来生成token,还有一个玩法,用户登录时,生成token的 SecretKey 是一个随机数,也就是说每个用户,每次登录时jwt SecretKey 是随机数,并保存到缓存,key是登录账户,(当然了,分布式缓存的话,就用Redis,sqlserver缓存等等),总之,客户端访问接口是,header 要带登录账户,和token,服务端拿到登录账号,到缓存去捞相应的SecretKey ,然后再进行token校验。可以防伪造token了(这个方案在一定程度上能防止伪造,但是不能防止token泄露被劫持)。

获取refresh token的方法#

ASP.NET Core应用JWT进行用户认证及Token的刷新方案

参考#

Java登录功能实现token生成与验证

PHP实现JWT的Token登录认证

JWT使用详解

JWT官网

以上所述是小编给大家介绍的Token登陆验证机制的原理及实现,希望对大家有所帮助。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • Java登录功能实现token生成与验证

    一.token与cookie相比较的优势 1.支持跨域访问,将token置于请求头中,而cookie是不支持跨域访问的: 2.无状态化,服务端无需存储token,只需要验证token信息是否正确即可,而session需要在服务端存储,一般是通过cookie中的sessionID在服务端查找对应的session: 3.无需绑定到一个特殊的身份验证方案(传统的用户名密码登陆),只需要生成的token是符合我们预期设定的即可: 4.更适用于移动端(Android,iOS,小程序等等),像这种原生平台不

  • koa+jwt实现token验证与刷新功能

    JWT JSON Web Token (JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的.自包含的方式,用于作为JSON对象在各方之间安全地传输信息.该信息可以被验证和信任,因为它是数字签名的. 本文只讲Koa2 + jwt的使用,不了解JWT的话请到这里)进行了解. koa环境 要使用koa2+jwt需要先有个koa的空环境,搭环境比较麻烦,我直接使用koa起手式,这是我使用koa+typescript搭建的空环境,如果你也经常用koa写写小demo,可以点个star,方便~ 安

  • 基于Java验证jwt token代码实例

    这篇文章主要介绍了基于Java验证jwt token代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 How to load public certificate from pem file..?地址 1.HS256对称加密 package jwt; import java.io.FileInputStream; import java.io.IOException; import java.security.KeyFactory; im

  • JAVA中的Token 基于Token的身份验证实例

    最近在做项目开始,涉及到服务器与安卓之间的接口开发,在此开发过程中发现了安卓与一般浏览器不同,安卓在每次发送请求的时候并不会带上上一次请求的SessionId,导致服务器每次接收安卓发送的请求访问时都新建一个Session进行处理,无法通过传统的绑定Session来进行保持登录状态和通讯状态. 基于传统方法无法判断安卓的每次请求访问状态,故查询资料了解到Token,特殊的身份证验证.以下是网上搜寻资料所得,作为学习总结资料. 令牌是一种能够控制站点占有媒体的特殊帧,以区别数据帧及其他控制帧.to

  • Token登陆验证机制的原理及实现

    session简介 做过Web开发的程序员应该对Session都比较熟悉,Session是一块保存在服务器端的内存空间,一般用于保存用户的会话信息. 用户通过用户名和密码登陆成功之后,服务器端程序会在服务器端开辟一块Session内存空间并将用户的信息存入这块空间,同时服务器会在cookie中写入一个Session_id的值,这个值用于标识这个内存空间. 下次用户再来访问的话会带着这个cookie中的session_id,服务器拿着这个id去寻找对应的session,如果session中已经有了

  • vue+koa2实现session、token登陆状态验证的示例

    Session 登陆与 Token 登陆的区别 1.Session 登陆是在服务器端生成用户相关 session 数据,发给客户端 session_id 存放到 cookie 中,这样在客户端请求时带上 session_id 就可以验证服务器端是否存在 session 数据,以此完成用户认证.这种认证方式,可以更好的在服务端对会话进行控制,安全性比较高(session_id 随机),但是服务端需要存储 session 数据(如内存或数据库),这样无疑增加维护成本和减弱可扩展性(多台服务器). C

  • token工作机制及原理附Java生成token工具类

    什么是token Token是服务端生成的一串字符串,以作客户端进行请求的一个令牌,当第一次登录后,服务器生成一个Token便将此Token返回给客户端,以后客户端只需带上这个Token前来请求数据即可,无需再次带上用户名和密码. 基于 Token 的身份验证使用基于 Token 的身份验证方法,在服务端不需要存储用户的登录记录.流程是这样的:客户端使用用户名跟密码请求登录服务端收到请求,去验证用户名与密码验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端客户端收到 T

  • go gin+token(JWT)验证实现登陆验证

    1.准备 go get github.com/dgrijalva/jwt-go go get github.com/gin-gonic/gin  2.代码 package main import ( "errors" "fmt" "github.com/dgrijalva/jwt-go" "github.com/gin-gonic/gin" "net/http" "time" ) fun

  • springboot+jwt实现token登陆权限认证的实现

    一 前言 此篇文章的内容也是学习不久,终于到周末有时间码一篇文章分享知识追寻者的粉丝们,学完本篇文章,读者将对token类的登陆认证流程有个全面的了解,可以动态搭建自己的登陆认证过程:对小项目而已是个轻量级的认证机制,符合开发需求: 二 jwt实现登陆认证流程 用户使用账号和面发出post请求 服务器接受到请求后使用私钥创建一个jwt,这边会生成token 服务器返回这个jwt给浏览器 浏览器需要将带有token的jwt放入请求头 每次手到客户端请求,服务器验证该jwt的token 验证成功返回

  • 通过Spring Security魔幻山谷讲解获取认证机制核心原理

    本文基于Springboot+Vue+Spring Security框架而写的原创学习笔记,demo代码参考<Spring Boot+Spring Cloud+Vue+Element项目实战:手把手教你开发权限管理系统>一书. 这是一个古老的传说. 在神秘的Web系统世界里,有一座名为SpringSecurity的山谷,它高耸入云,蔓延千里,鸟飞不过,兽攀不了.这座山谷只有一条逼仄的道路可通.然而,若要通过这条道路前往另一头的世界,就必须先拿到一块名为token的令牌,只有这样,道路上戍守关口

  • Vue 和 Django 实现 Token 身份验证的流程

    目录 基于 Token 的验证流程 Token 的组成 Header Payload Signature 加密算法 Django 生成和验证 Token 处理 Token 登录成功批发 Token 中间件拦截验证 (Middleware) Vue 存储和携带 Token 登录成功存储 Token 请求头携带用户名和 Token 使用 Django 编写的 B/S 应用通常会使用 Cookie + Session 的方式来做身份验证,用户登录信息存储在后台数据库中,前端 Cookie 也会存储少量

  • java中注解机制及其原理的详解

    java中注解机制及其原理的详解 什么是注解 注解也叫元数据,例如我们常见的@Override和@Deprecated,注解是JDK1.5版本开始引入的一个特性,用于对代码进行说明,可以对包.类.接口.字段.方法参数.局部变量等进行注解.它主要的作用有以下四方面: 生成文档,通过代码里标识的元数据生成javadoc文档. 编译检查,通过代码里标识的元数据让编译器在编译期间进行检查验证. 编译时动态处理,编译时通过代码里标识的元数据动态处理,例如动态生成代码. 运行时动态处理,运行时通过代码里标识

  • React从react-router路由上做登陆验证控制的方法

    本文介绍了React从react-router路由上做登陆验证控制的方法,分享给大家,具体如下: 验证代码 import React from 'react' import {connect} from 'react-redux'; function requireAuthentication(Component) { // 组件有已登陆的模块 直接返回 (防止从新渲染) if (Component.AuthenticatedComponent) { return Component.Authe

  • thinkphp5框架API token身份验证功能示例

    本文实例讲述了thinkphp5框架API token身份验证功能.分享给大家供大家参考,具体如下: 使用说明:登陆时生成token和刷新用的refresh_token,返回给客户端,客户端收到保存本地localStorage等,每次访问接口带上token,后端验证token存在并且一致后方可执行接下来的动作,假如不存在就返回token过期,客户端调用刷新接口传入token和refresh_token,服务器端进行验证,验证通过重新生成新的token保存数据库,返回给客户端客户端刷新本地toke

随机推荐