• Spring Boot学习04--使用JWT进行Token验证


    JWT(Json Web Token)是一种认证协议,在前后端分离的项目中,客户端向服务端发送的请求存在“跨域”的问题。而在分布式架构体系下,一般会有多个服务器提供服务。例如使用Nginx进行反向代理,使用轮询或根据负载的策略对服务器进行分配时,客户端每次请求的可能是不同的服务器。

    这两种情况下,传统的Session存储客户端身份的方式就会有很多的不便。而JWT是解决方案之一。

    1. Token的组成

    JWT的Token由三部分组成:头部(Header)、负载(Payload)、验证签名(Signature)。

    这三部分之间,使用英文句号"."分割,举例如下:

    首先有一个固定的明文的前缀:"Bearer "。

    "token": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOjUwMCwicmlkIjowLCJpYXQiOjE2MTExOTE3OTksImV4cCI6MTYxMTI3ODE5OX0.dCZFvxwJ0TS_fB_yj_6msveURl6xMYrsaaWraRqOA7Q"

    Header默认内容如下:

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

    将其进行Base64编码,得到的字符串为:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9。头部是紧跟在Bearer 后面的的内容。


    Payload中存储的是有效的信息,也是一个json格式,例如:

    {
        'id': 1,
        'username': "zhangsan",
        'gender': 0
    }

    对其进行Base64编码,得到字符串为:ewogICAgJ2lkJzogMSwKICAgICd1c2VybmFtZSc6ICJ6aGFuZ3NhbiIsCiAgICAnZ2VuZGVyJzogMAp9。

    Signature是根据两部分的信息进行签名得到的字符串,其签名规则为:

    HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

    注:这里加密算法HMACSHA256由头部来指定,secret是存储在服务端的秘钥。

    例如,对字符串"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOjUwMCwicmlkIjowLCJpYXQiOjE2MTExOTE3OTksImV4cCI6MTYxMTI3ODE5OX0",使用秘钥:"itcast",进行HMACSHA256进行加密,得到的结果为:"dCZFvxwJ0TS_fB_yj_6msveURl6xMYrsaaWraRqOA7Q"。这做为token的第三部分。

    2.在Spring Boot项目中使用JWT进行Token验证

    首先在pom文件中添加JWT的坐标

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

    编写工具类,实现Token的生成和验证逻辑:

     1 package com.example.demo.utils;
     2 
     3 import com.auth0.jwt.JWT;
     4 import com.auth0.jwt.JWTCreator;
     5 import com.auth0.jwt.JWTVerifier;
     6 import com.auth0.jwt.algorithms.Algorithm;
     7 import com.auth0.jwt.interfaces.DecodedJWT;
     8 
     9 import java.util.Calendar;
    10 import java.util.Date;
    11 import java.util.Map;
    12 
    13 public class JWTUtils {
    14 
    15     public static final String secret = "mysecret";
    16 
    17     //生成token
    18     public static String getToken(Map<String,String> map){
    19         Calendar instance = Calendar.getInstance();
    20         Date date = instance.getTime();
    21         instance.add(Calendar.DATE,1);
    22 
    23         JWTCreator.Builder builder = JWT.create();
    24         map.forEach( (k,v) -> {
    25             builder.withClaim(k,v);
    26         });
    27 
    28         String token = builder
    29                 .withIssuedAt(date)
    30                 .withExpiresAt(instance.getTime())
    31                 .sign(Algorithm.HMAC256(secret));
    32 
    33         return token;
    34     }
    35 
    36     public static DecodedJWT verify(String token){
    37         JWTVerifier build = JWT.require(Algorithm.HMAC256(secret)).build();
    38         DecodedJWT verify = build.verify(token);
    39         return verify;
    40     }
    41 }

    编写拦截器,实现对HTTP请求中的Token自动验证:

     1 package com.example.demo.interceptors;
     2 
     3 import com.auth0.jwt.interfaces.DecodedJWT;
     4 import com.example.demo.utils.JWTUtils;
     5 import com.fasterxml.jackson.databind.ObjectMapper;
     6 import org.springframework.web.servlet.HandlerInterceptor;
     7 
     8 import javax.servlet.http.HttpServletRequest;
     9 import javax.servlet.http.HttpServletResponse;
    10 import java.util.HashMap;
    11 import java.util.Map;
    12 
    13 public class JWTInterceptor implements HandlerInterceptor {
    14     @Override
    15     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    16         Map<String,Object> map = new HashMap<>();
    17         String token = request.getHeader("Authorization");
    18         try{
    19             DecodedJWT verify = JWTUtils.verify(token);
    20             return true;
    21         }
    22         catch (Exception e){
    23             e.printStackTrace();
    24             map.put("state",false);
    25             map.put("msg","请求失败");
    26         }
    27         String json = new ObjectMapper().writeValueAsString(map);
    28         response.setContentType("application/json;charset=utf-8");
    29         response.getWriter().println(json);
    30         return false;
    31     }
    32 }

    编写Controller对Token接受请求,并处理:

     1 package com.example.demo.controller;
     2 
     3 import com.alibaba.fastjson.JSON;
     4 import com.alibaba.fastjson.JSONObject;
     5 import com.auth0.jwt.interfaces.Claim;
     6 import com.auth0.jwt.interfaces.DecodedJWT;
     7 import com.example.demo.model.dto.SPManager;
     8 import com.example.demo.model.out.LoginData;
     9 import com.example.demo.model.out.LoginResult;
    10 import com.example.demo.model.out.Meta;
    11 import com.example.demo.service.SPManagerService;
    12 import com.example.demo.utils.JWTUtils;
    13 
    14 import org.springframework.beans.factory.annotation.Autowired;
    15 import org.springframework.web.bind.annotation.PostMapping;
    16 import org.springframework.web.bind.annotation.RequestMapping;
    17 import org.springframework.web.bind.annotation.RequestParam;
    18 import org.springframework.web.bind.annotation.RestController;
    19 
    20 import javax.servlet.http.HttpServletRequest;
    21 import java.util.HashMap;
    22 
    23 @RestController
    24 public class ManagerController {
    25 
    26     @Autowired
    27     SPManagerService spManagerService;
    28 
    29     @PostMapping("/login")
    30     public JSONObject Login(@RequestParam String username, @RequestParam String password) {
    31         System.out.println(username + "|" + password);
    32         
    33         LoginData lt = new LoginData();
    34         Meta meta = new Meta();
    35         SPManager model = spManagerService.getManagerByNameAndPwd(username, password);
    36         System.out.println(model);
    37         if (model != null) {
    38             HashMap<String, String> map = new HashMap<>();
    39             map.put("uid", model.getMgId().toString());
    40             map.put("rid", model.getRoleId().toString());
    41             String token = JWTUtils.getToken(map);
    42 
    43             lt.setId(model.getMgId());
    44             lt.setRid(model.getRoleId());
    45             lt.setUsername(model.getMgName());
    46             lt.setEmail(model.getMgEmail());
    47             lt.setMobile(model.getMgMobile());
    48             lt.setToken(token);
    49 
    50             meta.setMsg("登录成功");
    51             meta.setStatus(200);
    52         }else{
    53             lt = null;
    54             meta.setMsg("登录失败");
    55             meta.setStatus(400);
    56         }
    57         LoginResult lr = new LoginResult();
    58         lr.setData(lt);
    59         lr.setMeta(meta);
    60 
    61         String json = JSON.toJSONString(lr);
    62         JSONObject jsonObject = JSONObject.parseObject(json);
    63         return jsonObject;
    64     }
    65 }

    在拦截器JWTInterceptor中已经定义了对request头[Authorization]中存储的Token自动验签的处理的逻辑,请求只有通过了拦截器的验证,才能进入到Controller中。这样在具体的业务逻辑处理时就无需编写重复的验证逻辑了。

  • 相关阅读:
    display、box-sizing,position有哪些值?
    css伪类与伪元素
    HTML基础(一)——一般标签、常用标签和表格
    C#处理猜拳问题(非窗体)
    C#语言基础——结构体和枚举类型
    C#语言基础-类——string增加内容
    C#解决验证码问题
    C#ArrayList集合——小例题
    C#语言基础——特殊集合
    http请求访问响应慢问题解决的基本思路
  • 原文地址:https://www.cnblogs.com/asenyang/p/14306349.html
Copyright © 2020-2023  润新知