ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

3.JWT的初步实现(仅为个人学习)

2021-07-22 20:31:02  阅读:92  来源: 互联网

标签:map 拦截器 JWT new 初步 token 仅为 import public


一.JWT概述

JWT(JSON WEB Token)是一个标准,借助JSON格式数据作为WEB应用请求中的令牌,进行数据的自包含设计,实现各方安全的信息传输,在数据传输过程中还可以对数据进行加密,签名等相关处理。同时JWT也是目前最流行的跨域身份验证解决方案(其官方网址为:https://jwt.io/)。可以非常方便的在分布式系统中实现用户身份认证。

二.JWT数据结构

JWT通常由三部分构成,分别为Header(头部)Payload(负载),Signature(签名),其格式如下:

三.流程步骤

1.环境准备

第一步:创建项目

第二步:添加Jwt依赖   

  <!--添加jwt依赖-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>      
        </dependency>

第三步:创建配置文件application.yml (暂时不写任何内容)

第四步:定义启动类

第五步:运行启动类,检测是否可成功启动

2.创建和解析token(本代码在测试类中)

自定义负载信息,失效时间 重要

在定义失效时间时,也可以使用java中的Calendar方法,不过在java8之后就不推荐使用了,

                        Calendar calendar=Calendar.getInstance();

                        calendar.add(Calendar.MINUTE, 30);

                        Date expirationTime=calendar.getTime();     

                这里定义完之后,后面的链式调用需要这么写才行   .setExpiration(calendar.getTime())    

第二张图为另一种写法                     

package com.cy.jt.security;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import java.sql.SQLOutput;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@SpringBootTest
public class JwtTsets {
    private String secret="13333585948";
    /**
     * 测试创建和解析token
     * */
    @Test
    void testCreateAndParseToken(){

        //1.创建一个token(令牌中包含三部分:头信息(标题),负载信息(内容),签名信息(给信息加密))
        //1.1获取登录认证
        Map<String, Object> map = new HashMap<>();
        map.put("username", "jack");
        map.put("permissions","sys:res:create,sys:res:retrieve");
        //1.2基于JWt规范创建token对象(令牌--也就是通票)
        //Jwts为引入的一个依赖的类



        String token = Jwts.builder()               //创建token
                .setSubject("haha")              //主体对象  好比一个代表
                .setClaims(map)                     //自定义负载信息(存储登陆用户信息)            *******************
                .setExpiration(new Date(System.currentTimeMillis()+30*1000))  //失效时间     currentime为有效时间  (标准负载信息)  *****************************
                .setIssuedAt(new Date())            //当前时间     (标准负载信息)
                .signWith(SignatureAlgorithm.HS256,secret)    //信息加密算法(签名加密)      secret加密盐  随便定义 不能给人(密钥)
                .compact();//令牌  生成token
        System.out.println(token);
//2.解析token内容
        Claims body = Jwts.parser()  //拿到解析对象
                .setSigningKey(secret)   //设置解析时,使用的密钥
                .parseClaimsJws(token)   //获取token中的负载
                .getBody();//获取具体内容
        System.out.println(body);
    }
}

@Test
void testCreateAndParseToken(){
    //1.创建令牌
    //1.1定义负载信息
    Map<String,Object> map=new HashMap<>();
    map.put("username", "jack");
    map.put("permissions", "sys:res:create,sys:res:retrieve");
    //1.2定义过期实践
    Calendar calendar=Calendar.getInstance();
    calendar.add(Calendar.MINUTE, 30);
    Date expirationTime=calendar.getTime();
    //1.3定义密钥
    String secret="AAABBBCCCDDD";
    //1.4生成令牌
    String token= Jwts.builder()
            .setClaims(map)
            .setIssuedAt(new Date())
            .setExpiration(calendar.getTime())   这里为使用calendar定义的失效时间写法
            .signWith(SignatureAlgorithm.HS256,secret)
            .compact();
    System.out.println(token);
    //2.解析令牌
    Claims claims = Jwts.parser().setSigningKey(secret)
            .parseClaimsJws(token)
            .getBody();
    System.out.println("claims="+claims);
}

3.业务代码中的实现

3.1.创建一个Jwt类(类名随便起) 用于创建token,可看测试类的代码解释,下图为实现的代码

package com.cy.jt.security.util;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
import java.util.Map;
/**基于Jwt规范创建和解析token的工具类*/
public class JwtUtils {
    private static String secret="1231561";
    /**基于负载和算法创建token信息*/
    public static String generatorToken(Map<String,Object> map){
        return Jwts.builder()
                .setClaims(map)
                .setExpiration(new Date(System.currentTimeMillis()+30*60*1000))
                .setIssuedAt(new Date())
                .signWith(SignatureAlgorithm.HS256, secret)
                .compact();
    }
    /**解析token获取数据*/
    public static Claims getClaimsFromToken(String token){
        return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
    }
    /** 判定token是否有效*/
    public static boolean isTokenExpired(String token){
        Date expiration = getClaimsFromToken(token).getExpiration();
        return expiration.before(new Date());
    }
}

 3.2.定义AuthController用于处理登录认证业务,代码如下:

package com.cy.jt.security.conller;

import com.cy.jt.security.util.JwtUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;

@RestController
public class AuthController {
    @RequestMapping("/login")
    public Map<String,Object> dologin(String username,
                                      String password){
        Map<String, Object> map = new HashMap<>();
        if("jack".equals(username)&&"123456".equals(password)){
            map.put("state","200");
            map.put("msg", "login ok");
            Map<String,Object> claims = new HashMap<>();
            claims.put("username", username);
            //JwtUtils.generatorToken(claims)  调用这个方法来创建username的token信息
            map.put("dadaaaaaaaaa", JwtUtils.generatorToken(claims)); //根据类名调用generatorToken方法
            return map;
        }else{
            map.put("state", "201");
            map.put("mas", "login fiure");
            return map;
        }
    }
}

3.3.定义一个资源服务对象,登录成功以后可以访问此对象中的方法,例如:

package com.cy.jt.security.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ResourceController {

    @RequestMapping("/retrieve")
    public String doRetrieve(){
        //检查用户有没有登录
        //执行业务查询操作
        return "do retrieve resource success";
    }
    @RequestMapping("/update")
    public String doUpdate(){
        //检查用户有没有登录
        //执行业务更新操作
        return "do update resource success";
    }
}

 3.4 定义拦截器

假如,每次在访问查询,更新,删除,修改操作时,都需要验证用户有没有登录,在每一个方法中都得验证一次,这样代码的冗余就比较大,我们可以写一个springMVC得拦截器,在拦截器中进行用户身份检测,例如:

3.4.1   拦截器代码段    当你定义了一个拦截器后,需要写一个配置类,把拦截器添加到执行链中,才能执行到拦截器

           代码在图二

package com.cy.jt.security.Interceptor;
import com.cy.jt.security.util.JwtUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * 令牌(token:ticker-通票)拦截器
 * 其中,HandlerInterceptor为Spring MVC中的拦截器,
 * 可以在Controller方法执行之前之后执行一些动作.
 *  1)Handler 处理器(Spring MVC中将@RestController描述的类看成是处理器)
 *  2)Interceptor 拦截器
 * */
public class TokenInterceptor implements HandlerInterceptor {
   /**
    * preHandle在目标controller方法执行之前执行
    * */
    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) throws Exception {
        System.out.println("============");
        String token = request.getParameter("dadaaaaaaaaa");
        //判定请求中是否有令牌
        if(token==null||"".equals(token))
            throw new RuntimeException("please login");
        boolean flag = JwtUtils.isTokenExpired(token);
        //判定令牌是否已经过期
        if(flag)
            throw new RuntimeException("login timeout,please login");
        //true表示放行,false表示拦截到请求以后,不再继续传递
        return false;  //false表示请求不在继续传递
    }
//    /**在方法执行之前执行*/
//    @Override
//    public boolean preHandle(HttpServletRequest request,
//                             HttpServletResponse response,
//                             Object handler) throws Exception {
//        return false;
//    }
//
//    /**在方法执行之后执行*/
//    @Override
//    public void postHandle(HttpServletRequest request,
//                           HttpServletResponse response,
//                           Object handler, ModelAndView modelAndView) throws Exception {
//
//    }
}

 添加执行拦截器的配置类

package com.cy.jt.security.config;

import com.cy.jt.security.Interceptor.TokenInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * 需要写一个配置类把拦截器添加到执行链中,才能执行拦截器
    实现WebMvcConfigurer ??????
 * */
@Configuration
public class SpringWebConfig implements WebMvcConfigurer {
   //将拦截器添加到spring mvc执行链中
    //registry  此对象提供一个list集合,可以将拦截器添加到集合中
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //配置需要拦截的url
        registry.addInterceptor(new TokenInterceptor()).addPathPatterns("/retrieve","/update");
    }
}

注:上诉实现没有基于Nginx实现

图解:当客户端访问服务器(tomcat)时,tomcat会给客户端一个token密匙,这个token密匙会存在客户端,当客户端再次访问tomcat时,不一定会访问第一次访问的那个tomcat(客户端再次访问会带着token密匙),此时访问新的tomcat服务器时,如果客户端没有token密匙,就会重新登录,如果客户端有携带token密匙,就不用登陆。

 

 

标签:map,拦截器,JWT,new,初步,token,仅为,import,public
来源: https://blog.csdn.net/m0_56773332/article/details/119006721

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有