首页 > 其他分享 >使用 JWT 生成 token

使用 JWT 生成 token

时间:2022-11-17 18:25:43浏览次数:76  
标签:ResultVo 请求 resultVo JWT 生成 token new response

JWT 简介

  • JWT:Json Web Token

  • 官网:https://jwt.io

  • 优点:可生成安全性较高的 token 且可以完成时效性的检验(登陆过期检查)

  • JWT 结构:(由官网获取)

    image-20221116205641200

JWT 生成 token

添加依赖:

<!-- java-jwt -->
<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.18.2</version>
</dependency>
<!-- jjwt -->
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>

生成 token 示例代码:

//使用jwt生成token进行加密
JwtBuilder builder = Jwts.builder();

//此map可以存储用户角色权限信息
Map<String, Object> map = new HashMap<>();
map.put("k1", "v1");

//链式调用,设置相关加密信息
String token = builder.setSubject(name) //设置主题,也就是设置token中携带的数据
    .setIssuedAt(new Date()) //设置token生成时间
    .setId(users.get(0).getUserId() + "") //设置token的id(此处用的用户id)
    .setClaims(map) //map中可存放用户角色权限信息
    .setExpiration(new Date(System.currentTimeMillis() + 24 * 60 * 60 * 1000)) //设置token过期时间为1天后
    .signWith(SignatureAlgorithm.HS256, "luis333") //设置加密方式和加密密码
    .compact();

JWT 解析 token

//获取token并校验
if (token == null) {
    return new ResultVo(ResStatus.NO, "请先登陆!", null);
} else {

    //获取jwt解析器
    JwtParser parser = Jwts.parser();
    parser.setSigningKey("luis333"); //之前加密时的加密密码,一致才能解析成功

    try {
        //如果token正确(密码正确,且在有效期内)则正常执行,否则抛出异常
        Jws<Claims> claimsJws = parser.parseClaimsJws(token); //解析token

        //获取解析的token中相关数据
        Claims body = claimsJws.getBody(); //获取token中用户数据
        String subject = body.getSubject(); //获取subject中数据
        String v1 = body.get("k1", String.class); //获取claims中存储的map中数据

        return new ResultVo(ResStatus.OK, "success", null);
    } catch (Exception e) {
        return new ResultVo(ResStatus.NO, "登陆过期,请重新登陆!", null);
    }
}

拦截器校验 token

请求非常多,一个一个地进行校验不现实,所以需要统一校验 token,此时可以使用拦截器。

在拦截器的预处理方法中进行 token 统一校验,校验通过则放行请求,不通过则做出相关响应提示。

在拦截器统一校验 token 后,在控制器中做过校验的请求就不需要再次进行校验了,直接写业务逻辑即可。

拦截器类:

/**
 * 拦截器
 */
@Component
public class CheckTokenInterceptor implements HandlerInterceptor {

    /**
     * 预处理方法,拦截请求,决定是否放行。
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        //获取token并校验
        String token = request.getParameter("token");
        System.out.println("preHandle ========> token = " + token);
        if (token == null) {
            //没有token
            ResultVo resultVo = new ResultVo(ResStatus.NO, "请先登录!", null);
            doResponse(response, resultVo);
        } else {
            //获取jwt解析器
            JwtParser parser = Jwts.parser();
            parser.setSigningKey("luis333"); //之前加密时的加密密码,一致才能解析成功
            try {
                //如果token正确(密码正确,且在有效期内)则正常执行,否则抛出异常
                Jws<Claims> claimsJws = parser.parseClaimsJws(token); //解析token
                return true;
            } catch (ExpiredJwtException e) {
                ResultVo resultVo = new ResultVo(ResStatus.NO, "token已过期!", null);
                doResponse(response, resultVo);
            } catch (UnsupportedJwtException e) {
                ResultVo resultVo = new ResultVo(ResStatus.NO, "异常token!", null);
                doResponse(response, resultVo);
            } catch (Exception e) {
                ResultVo resultVo = new ResultVo(ResStatus.NO, "请先登录!", null);
                doResponse(response, resultVo);
            }
        }
        return false;
    }

    /**
     * 响应流程封装
     */
    private void doResponse(HttpServletResponse response, ResultVo resultVo) throws IOException {
        response.setContentType("application/json");
        response.setCharacterEncoding("utf-8");
        PrintWriter out = response.getWriter();
        String s = new ObjectMapper().writeValueAsString(resultVo);
        out.print(s);
        out.flush();
        out.close();
    }
}

拦截器配置类:

/**
 * 拦截器配置类(SpringBoot中配置拦截器)
 */
@Configuration
public class InterceptorConfig implements WebMvcConfigurer { //注意此处需要实现WebMvcConfigurer接口

    @Autowired
    private CheckTokenInterceptor checkTokenInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(checkTokenInterceptor) //添加拦截器
                .addPathPatterns("/shopcart/**") //添加要拦截的请求
                .addPathPatterns("/orders/**")
                .excludePathPatterns("/user/**"); //放行的请求
    }
}

常用请求头传递 token

前端但凡访问受限资源,都必须携带 token 发起请求;token 可以通过请求行(params)、请求头(headers)以及请求体(data)传递,但是习惯性使用 headers 传递!

在实际开发中,发送请求时,我们一般都是在请求头中来传递 token,通过自定义请求头数据,传递 token 到后端。

前端使用自定义请求头数据传递 token 示例:(注意请求头传递数据关键字 headers,带 s)

<script type="text/javascript">
			
    var baseUrl = "http://localhost:8080";
    var vm = new Vue({
        el: "#container",
        data: {
            token: ""
        },
        //钩子函数,生命周期函数,直接定义!
        created: function() {
            //钩子函数,data数据初始化之后自动调用
            console.log("========> created method execute !")

            var token = getCookieValue("token");
            this.token = token;
            console.log("token = " + token);

            axios({
                url: baseUrl + "/shopcart/list",
                method: "get",
                headers: {token: this.token} //自定义请求头数据传递token
            }).then(function(res) {
                console.log(res.data);
            });
        }
    });
</script>

注意:使用自定义请求头传递数据时,浏览器会自动发起一次预检请求(method="OPTIONS"),来监测环境是否畅通,如果服务器正常响应,则后续请求才可正常发起。

image-20221117135445443

所以,当使用拦截器统一校验 token ,并且使用自定义请求头传递 token 时,需要在拦截器中放行浏览器自动发起的预检请求,即放行 OPTIONS 请求方式的预检请求。

主要注意点:

image-20221117144930253

拦截器代码示例:

/**
 * 拦截器
 */
@Component
public class CheckTokenInterceptor implements HandlerInterceptor {

    /**
     * 预处理方法,拦截请求,决定是否放行。
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        //放行浏览器自动发起的预检请求(请求方式为OPTIONS)
        String method = request.getMethod();
        System.out.println("method ========> " + method);
        if ("OPTIONS".equalsIgnoreCase(method)) {
            return true;
        }

        //从请求头中获取token并校验
        String token = request.getHeader("token");
        System.out.println("preHandle ========> token = " + token);
        if (token == null) {
            //没有token
            ResultVo resultVo = new ResultVo(ResStatus.NO, "请先登录!", null);
            doResponse(response, resultVo);
        } else {
            //获取jwt解析器
            JwtParser parser = Jwts.parser();
            parser.setSigningKey("luis333"); //之前加密时的加密密码,一致才能解析成功
            try {
                //如果token正确(密码正确,且在有效期内)则正常执行,否则抛出异常
                Jws<Claims> claimsJws = parser.parseClaimsJws(token); //解析token
                return true;
            } catch (ExpiredJwtException e) {
                ResultVo resultVo = new ResultVo(ResStatus.NO, "token已过期!", null);
                doResponse(response, resultVo);
            } catch (UnsupportedJwtException e) {
                ResultVo resultVo = new ResultVo(ResStatus.NO, "异常token!", null);
                doResponse(response, resultVo);
            } catch (Exception e) {
                ResultVo resultVo = new ResultVo(ResStatus.NO, "请先登录!", null);
                doResponse(response, resultVo);
            }
        }
        return false;
    }

    /**
     * 响应流程封装
     */
    private void doResponse(HttpServletResponse response, ResultVo resultVo) throws IOException {
        response.setContentType("application/json");
        response.setCharacterEncoding("utf-8");
        PrintWriter out = response.getWriter();
        String s = new ObjectMapper().writeValueAsString(resultVo);
        out.print(s);
        out.flush();
        out.close();
    }
}

标签:ResultVo,请求,resultVo,JWT,生成,token,new,response
From: https://www.cnblogs.com/luisblog/p/16900357.html

相关文章

  • NumPy切片或直接赋值生成数组视图
    1先创建一个ndarry数组aimportnumpyasnpa=np.arange(start=1,stop=10,step=2)print(a)[13579]2将a切片赋值于一个数组bb=a[0:1]print(b)[1]3......
  • .NET Core 项目Linux环境下生成二维码
    问题:公司系统开发中,需要对企微授权链接进行二维码生成,然后向客户提供;当然,首当其冲想到的是使用ZXing.NET库进行实现,毕竟生成简单二维码也就那几句代码;然而,在本地环境中,一......
  • 自动生成前端接口文件以及方法函数实践
    实现原理解析(以个人项目角度实现)后端接口布置访问链接,可以从浏览器network中获取到请求地址存在请求参数为userpageSize访问接口示例为:/apiList/pageSize=55获取......
  • 11.django-csrftoken
    django为用户实现防止跨站请求伪造的功能,通过中间件django.middleware.csrf.CsrfViewMiddleware来完成。而对于django中设置防跨站请求伪造功能有分为全局和局部。CSRF(C......
  • JwtUtils
    packagecom.java1234.utils;importcom.java1234.common.JwtConstant;importcom.java1234.entity.CheckResult;importio.jsonwebtoken.*;importorg.bouncycastle.......
  • 使用 Go HTTP 框架 Hertz 进行 JWT 认证
    前言上一篇文章简单介绍了一个高性能的GoHTTP框架——Hertz,本篇文章将围绕Hertz开源仓库的一个demo,讲述如何使用Hertz完成JWT的认证与授权流程。这里要说明的......
  • SpringClouldAlibaba 之 Sentinel流控规则同步到nacos(并重新生成镜像)
    前言上一篇我们将流控规则配置到了nacos让服务启动时拉取流控规则从而实现持久化但是是有一个缺陷的,毕竟在nacos中维护这个流控规则不太友好,毕竟sentinel为我们提供了可视......
  • 最小生成树
    最小生成树定义我们定义无向连通图的最小生成树(MinimumSpanningTree,MST)为边权和最小的生成树。注意:只有连通图才有生成树,而对于非连通图,只存在生成森林。题目链接......
  • CSS content内容生成技术以及应用
    一、简介content属性早在CSS2.1的时候就被引入了,可以使用​​:before​​​以及​​:after​​​伪元素生成内容。此特性目前已被大部分的浏览器支持:(Firefox1.5+,Safari......
  • 查看MySQL数据库所有的表名、表注释、字段名称、类型、长度、备注,一键导出生成数据库
    一、先了解下INFORMATION_SCHEMA1、在MySQL中,把INFORMATION_SCHEMA看作是一个数据库,确切说是信息数据库。其中保存着关于MySQL服务器所维护的所有其他数据库的信息。如数据......