JWT的使用流程

什么是JWT 

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

传统的 session 流程

  1. 浏览器发起请求登陆
  2. 服务端验证身份,生成身份验证信息,存储在服务端,并且告诉浏览器写入 Cookie
  3. 浏览器发起请求获取用户资料,此时 Cookie 内容也跟随这发送到服务器
  4. 服务器发现 Cookie 中有身份信息,验明正身
  5. 服务器返回该用户的用户资料

JWT 流程

  1. 浏览器发起请求登陆
  2. 服务端验证身份,根据算法,将用户标识符打包生成 token, 并且返回给浏览器
  3. 浏览器发起请求获取用户资料,把刚刚拿到的 token 一起发送给服务器
  4. 服务器发现数据中有 token,验明正身
  5. 服务器返回该用户的用户资料

区别

  1. session 存储在服务端占用服务器资源,而 JWT 存储在客户端
  2. session 存储在 Cookie 中,存在伪造跨站请求伪造攻击的风险
  3. session 只存在一台服务器上,那么下次请求就必须请求这台服务器,不利于分布式应用
  4. 存储在客户端的 JWT 比存储在服务端的 session 更具有扩展性

弊端

JWT中设置过期时间后必须等过期时间到后失效并不能随着登出失效,不过可以结合Redis进行使用,将Token存储在Redis中,设置Redis的过期时间

使用demo

一、引入包(其他诸如redis的包这边没列出)

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

二、编写类JwtHelper

package com.zhanghf.jwt;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.time.DateUtils;

import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.Map;

public class JwtHelper {
  
  private static final String  SECRET = "session_secret";  //生成token的前缀
  
  private static final String  ISSUER = "heaven_token";  //定义发布者
  

  //生成token
  public static String genToken(Map<String, String> claims){
    try {
      Algorithm algorithm = Algorithm.HMAC256(SECRET);  //tocken生成的算法
      JWTCreator.Builder builder = JWT.create().withIssuer(ISSUER).withExpiresAt(DateUtils.addDays(new Date(), 1)); //设置过期时间为1天
      claims.forEach((k,v) -> builder.withClaim(k, v));  //将claims存储到token中
      return builder.sign(algorithm).toString();  //签名并且返回token
    } catch (IllegalArgumentException | UnsupportedEncodingException e) {
      throw new RuntimeException(e);
    }
  }

  //验证token
  public static Map<String, String> verifyToken(String token)  {
    Algorithm algorithm = null;
    try {
      algorithm = Algorithm.HMAC256(SECRET);
    } catch (IllegalArgumentException | UnsupportedEncodingException e) {
      throw new RuntimeException(e);
    }
    JWTVerifier verifier = JWT.require(algorithm).withIssuer(ISSUER).build();
    DecodedJWT jwt =  verifier.verify(token);
    Map<String, Claim> map = jwt.getClaims();
    Map<String, String> resultMap = Maps.newHashMap();
    map.forEach((k,v) -> resultMap.put(k, v.asString()));
    return resultMap;
  }

}

上述中的SECRET和ISSUER分别为生成token的前缀和定义发布者,可自行修改。genToken方法里面设置过期时间为1天,也可自己定义。

三、登录、鉴权、登录代码

package com.zhanghf.jwt;

import com.google.common.collect.ImmutableMap;
import redis.clients.jedis.Jedis;

import java.time.Instant;
import java.util.Map;

/**
 * Created by YQ11053 on 2019/1/5 0005.
 */
public class JwtDemo {

   static Jedis jedis = new Jedis("127.0.0.7",6379);

    public static void main(String[] args){
//        String token = auth("test@qq.com","123456");
//        String token = getLoginedUserByToken("eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJtb29jX3VzZXIiLCJuYW1lIjoiNDQxMzM5OTA1QHFxLmNvbSIsImV4cCI6MTU0NjgyNzEyNywiZW1haWwiOiIxMjM0NTYiLCJ0cyI6IjE1NDY3NDA3MjcifQ.yAunUJCDP_szq5wQbsoCAlga-FFzwLWiI-IETSXGwCc");
//        System.out.println("token:"+token);
        invalidate("eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJtb29jX3VzZXIiLCJuYW1lIjoiNDQxMzM5OTA1QHFxLmNvbSIsImV4cCI6MTU0NjgyNzEyNywiZW1haWwiOiIxMjM0NTYiLCJ0cyI6IjE1NDY3NDA3MjcifQ.yAunUJCDP_szq5wQbsoCAlga-FFzwLWiI-IETSXGwCc");
    }

    /******************************登录*************************************************/

    /**
     * 校验用户名密码、生成token并返回用户对象
     * @param email
     * @param passwd
     * @return
     */
    public static String auth(String email, String passwd) {
        String token =  onLogin(email,passwd);
        return token;
    }

    //生成token方法
    private static String onLogin(String userName,String email) {
        String token =  JwtHelper.genToken(ImmutableMap.of("email", email, "name", userName,"ts", Instant.now().getEpochSecond()+""));
        renewToken(token,email);
        return token;
    }

    //通过redis存储token,就可以随时修改token失效时间,不然只能在jwtHelper中设置的1天过期
    private static  String renewToken(String token, String email) {
        jedis.set(email,token);
        jedis.expire(email,300);
        return token;
    }

    /******************************鉴权*************************************************/

    public static String getLoginedUserByToken(String token) {
        Map<String, String> map = null;
        try {
            map = JwtHelper.verifyToken(token);
        } catch (Exception e) {
           System.out.println("错误");
        }
        String email =  map.get("email");
        Long expired = jedis.ttl(email);
        if (expired > 0L) {
            renewToken(token, email);
        }
        return token;
    }

    /******************************鉴权*************************************************/
    //登出设置token失效的方法
    public static void invalidate(String token) {
        Map<String, String> map = JwtHelper.verifyToken(token); //校验token
        jedis.del(map.get("email"));
    }

}

 

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
在Gin框架中使用JWT(JSON Web Token)可以实现份验证和授权功能。JWT是一种用于在网络应用间传递信息的安全方法,它由三部分组成:header、payload和signature[^1]。 下面是在Gin框架中使用JWT的示例代码[^2]: 1. 导入所需的包: ```go import ( "github.com/gin-gonic/gin" "github.com/dgrijalva/jwt-go" ) ``` 2. 定义JWT的密钥: ```go var jwtKey = []byte("your_secret_key") ``` 3. 创建一个JWT的Claims结构体,用于存储用户的信息: ```go type Claims struct { Username string `json:"username"` jwt.StandardClaims } ``` 4. 创建一个处理登录请求的路由: ```go func login(c *gin.Context) { var loginData LoginData if err := c.ShouldBindJSON(&loginData); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request"}) return } // 验证用户名和密码 if loginData.Username == "admin" && loginData.Password == "password" { // 创建JWT的Claims claims := &Claims{ Username: loginData.Username, StandardClaims: jwt.StandardClaims{ ExpiresAt: time.Now().Add(time.Hour * 24).Unix(), // 设置过期时间 }, } // 创建JWT token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) tokenString, err := token.SignedString(jwtKey) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to generate token"}) return } // 返回JWT给客户端 c.JSON(http.StatusOK, gin.H{"token": tokenString}) } else { c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid credentials"}) } } ``` 5. 创建一个需要身份验证的路由: ```go func protectedRoute(c *gin.Context) { // 从请求头中获取JWT authHeader := c.GetHeader("Authorization") if authHeader == "" { c.JSON(http.StatusUnauthorized, gin.H{"error": "Missing authorization header"}) return } // 解析JWT tokenString := authHeader[7:] // 去除Bearer前缀 claims := &Claims{} token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) { return jwtKey, nil }) if err != nil { if err == jwt.ErrSignatureInvalid { c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token signature"}) return } c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid token"}) return } if !token.Valid { c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"}) return } // 验证通过,继续处理请求 c.JSON(http.StatusOK, gin.H{"message": "Protected route"}) } ``` 6. 在路由中注册处理函数: ```go func main() { r := gin.Default() r.POST("/login", login) r.GET("/protected", protectedRoute) r.Run(":8080") } ``` 以上代码演示了在Gin框架中使用JWT进行身份验证和授权的基本流程。用户可以通过发送登录请求获取JWT,然后在需要身份验证的路由中将JWT放入请求头中进行验证。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值