Java - token的存储与获取

news2025/1/19 11:35:20

1. 获取token的工具类

问:为什么写工具类呢???
答:因为我们不知道前端将token怎么存储的,所以我们可以通过调用Token工具类来获取token。Token工具类会检查header、URL中的属性值、以及Cookie等等!!!

public class UserTokenUtil {

    public static String getToken(HttpServletRequest request, String tokenName) {
        String token = null;

        // 1. header
        token = request.getHeader(tokenName);
        if (StringUtils.isNotBlank(token)) {
            return token;
        }
        // 2. cookie
        Cookie[] cookies = request.getCookies();
        if (cookies != null && cookies.length != 0) {
            for (Cookie cookie : cookies) {
                if (cookie != null && tokenName.equals(cookie.getName())) {
                    token = cookie.getValue();
                    break;
                }
            }
        }
        if (StringUtils.isNotBlank(token)) {
            return token;
        }
        // 3. parameter
        token = request.getParameter(tokenName);
        return token;
    }
    
}

2. header存储token

2.1 前端存储token

第一步安装:js-cookie

npm install --save js-cookie

第二步引入:(这里以vue开发为例,在main.js中引入!)

// 全局应用Cookie
import Cookie from 'js-cookie'
Vue.prototype.$Cookie = Cookie

第三步:前端访问后端,得到token后进行存储。

// 向后端发送登录请求
this.axios({
  method: "post",
  headers: {
    // 测试header保存数据
    "hahah": "text_header_save_Data"
  },
  url: "http://" + that.$store.state.host + "/zm-task/login/goLogin",
  data: {
    "loginNumber": that.ruleForm.user,
    "password": that.ruleForm.pass
  }
}).then(function (res) {
  // console.log(res.data);
  //根据后端返回的状态查看账号是否正确
  if (res.data.code == 0) {
    // ===============  cookie的操作 ================
    // 博文: https://blog.csdn.net/qq_16828495/article/details/120783389

    // 保存token
    that.$Cookie.set("token", res.data.data.token);
    //登录成功后跳转到后台的个人信息界面
    that.$message.success("登录成功!");
    that.$router.push({path: "/userInfo"});
  } else {
    that.$message.error(res.data.message);
  }
})
.catch(err => {
  // 后端如果出现异常,前端会报401错误。 这里捕获401错误。
  //console.log(err.response.data)
  if (err.response != null) {
    this.$message.error(err.response.data.message);
  } else {
    this.$message.error("未知异常");
  }
})

2.2 访问携带token

axios({
  method: "get",
  headers: {
    // 传输token用于验证当前登录用户
    "token": that.$Cookie.get("token"),
  },
  url: "http://" + that.$store.state.host + "/zm-task/login/updateEmail",
  params:{
  	// 需要修改的邮箱属性
    "email": formName.email
  }
}).then(res => {
  // 直接显示后端传来的信息
  that.$message.success(res.data.message);
}).catch(err => {
  // 后端如果出现异常,前端会报401错误。 这里捕获401错误。
  if (err.response != null) {
    this.$message.error(err.response.data.message);
  } else {
    this.$message.error("未知异常");
  }
})

2.3 后端获取token并进行验证(拦截器中进行验证)

@Slf4j
public class UserLoginAuthInterceptor implements HandlerInterceptor {

    /**
     *
     * @param request : 请求(通过请求获取token登陆凭证)
     * @param response : 返回给前端的响应
     * @param handler : 该参数中包含了对应方法的信息。比如:方法中的参数类型、参数的注解、方法的注解等信息。
     * @return
     * @throws Exception : 向上抛出异常
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 排除资源请求
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }
        // 通过handler获取方法上面的Login注解
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Login login = handlerMethod.getMethod().getAnnotation(Login.class);
        //说明方法上面没有Login注解
        if (login == null){
            return true;
        }
        // 有Login注解,但是Login的属性值为false
        if (Boolean.FALSE.equals(login.loginRequired())){
            return true;
        }
        // 获取请求头中的token请求
        String token = request.getHeader("token");
        // 根据token获取登陆的用户信息(登陆账号, 登陆ip, 用户权限0、1、2)
        UserLoginModel userLoginModel = JWTUtil.tokenToUser(token, request);
        // 获取当前请求的ip地址!!!  (公网才有效果)
        String ipAddr = IPUtil.getIpAddr(request);
        if (StringUtils.isBlank(ipAddr)){
            throw new BizException(ServerEnum.IP_GET_ERROR);
        }
        if (userLoginModel == null){

            //todo redis保存ip地址,防止被爆刷接口

            throw new BizException(ServerEnum.LOGIN_ERROR);
        }
        // 这里只有线上测试才能有效果,非线上测试无效果! (ipAddr公网才能获取准确的IPv4)
        if (!ipAddr.equals(userLoginModel.getIP())){
            // 登陆IP 与 请求IP不相同,所以重新进行登陆
            log.error("登陆ip:{}, 请求ip:{}", userLoginModel.getIP(), ipAddr);

            //todo redis保存ip地址,防止被爆刷接口

            throw new BizException(ServerEnum.LOGIN_ERROR);
        }
        //使用ThreadLocal保存用户信息
        UserLoginInfoThreadLocalUtil.set(userLoginModel);
        return true;
    }

    /**
     * 在整个请求处理完毕后进行回调,也就是说视图渲染完毕或者调用方已经拿到响应。
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //防止内存泄漏
        UserLoginInfoThreadLocalUtil.clear();
    }
}

3. URL中的属性值

以这个地址为例:https://editor.csdn.net/md?articleId=125379150&name=Thomas
当进行Get或者Post请求的时候,在url后面添加参数便可以!!!

public class UserTokenUtil {

    public static String getToken(HttpServletRequest request, String tokenName) {
        String articleId = null;
        String name = null;
        // articleId = 125379150
        articleId = request.getParameter(articleId);
        // name = Thomas
        name = request.getParameter(name);
        return articleId + " " + name;
    }
    
}

4. Cookie

4.1 控制器代码

@RestController
@RequestMapping("/cookie")
public class CookieTestController {

    // http://localhost:8080/cookie/login/tokentoken?id=13213
    @GetMapping("/login/{token}")
    public void getLogin(HttpServletRequest request, HttpServletResponse response) throws IOException {
        //设置请求编码格式
        request.setCharacterEncoding("UTF-8");
        //设置响应编码格式
        response.setCharacterEncoding("UTF-8");
        //设置数据返回的类型
        response.setContentType("text/json");
        // 获取请求信息(参数id对应的值)
        Integer id = Integer.valueOf(request.getParameter("id"));
        // 原本想获取请求url中的值,但是无法通过request获取!!!!
        String token = request.getPathInfo();

        System.out.println(request.getMethod()); // GET
        System.out.println(request.getRequestURI()); // /cookie/login/tokentoken
        Enumeration<String> parameterNames = request.getParameterNames();
        while (parameterNames.hasMoreElements()){
            // id (说明只能获取路径?后面的参数,不能获取包含在路径中的参数!!!)
            System.out.println(parameterNames.nextElement());
        }
        // 添加cookie信息
        Cookie c1 = new Cookie("token_cxp_zm", "chsdiufvbndsufyvbnduh");
        Cookie c2 = new Cookie("cxp-love_zm", "hahahahaha---cxp---love=---zm");
        response.addCookie(c1);
        response.addCookie(c2);

        PrintWriter out = response.getWriter();
        out.write("XXXXXXX" + id + " == " + token);
        out.flush();//刷新该流的缓冲
        out.close();//关闭流
    }

    // http://localhost:8080/cookie/login/getCookie
    @GetMapping("/login/getCookie")
    public void getCookies(HttpServletRequest request, HttpServletResponse response) throws IOException {
        //设置数据返回的类型
        response.setContentType("text/json");
        //设置请求编码格式
        request.setCharacterEncoding("UTF-8");
        //设置响应编码格式
        response.setCharacterEncoding("UTF-8");
        String State = "fail";
        //获取Cookie信息数组
        Cookie[] cks = request.getCookies();
        if (cks != null){
            for(Cookie cookie : cks){
                System.out.println(cookie.getName() + "=" + cookie.getValue());
            }
        }
        PrintWriter out=response.getWriter();
        out.write("测试获取Cookie");
        out.flush();//刷新该流的缓冲
        out.close();//关闭流
    }

}

4.2 测试

  • 向Cookie中插入key - value值!!!
    在这里插入图片描述
  • 之后的Get或者Post请求,不需要我们主动去插入cookie,请求会自动携带cookie进行访问!!!
    在这里插入图片描述
    在这里插入图片描述
    讲解完毕!!!

注意
问题:因为后端去设置Cookie,会涉及跨域,但是cookie是不能跨域的。这就造成了页面跳转时请求头带不上cookie中的token。这时只要把Domain设置成.+一级域名那么就能解决cookie跨域的问题了。

Token的使用(两种方式):
1、 直接返回token字符,让前端同学进行存储(Cookie、localStorage、SessionStorage),请求时候手动去携带token!!
2、 后端同学设置cookie的时候,注意跨域问题即可!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/408986.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

快速生成Vue2或者vue3模板

1.点击文件&#xff0c;再点击首选项&#xff0c;然后选择用户片段&#xff1b; 2.在弹出来的输入框中&#xff0c;选择第一行vue.json或者第二行新建全局代码片段文件都可&#xff0c;都是为了打开vue.json文件&#xff1b; 3.把下面代码复制到vue.json文件里&#xff0c;然后…

vue3搭建教程(基于vite+create-vue+ element-plus)

前言2021年8月5日&#xff0c;Vue正式发布3.2版本&#xff0c;同时&#xff0c;Vue的作者尤雨溪还在个人微博称&#xff1a;“ < script setup > TS Volar 真香 ”&#xff1b;2022年1月22日&#xff0c;Vue官方宣布Vue3成为了新的默认版本。如今的Vue3已经势不可挡&a…

【JavaScript-进阶】详解数据类型,内存分配,API元素对象获取

目录 前言 1.数据类型 1.简单数据类型和复杂数据类型 2.堆和栈 2.webApi 1.API 2.DOM是啥&#xff1f; 3.如何获取元素&#xff1f; 1.根据ID获取 ​编辑 2.根据标签名获取 3.通过HTML5新增的方法获取 4.特殊元素获取(body,html) 总结 前言 祝大家中秋节快乐…

Vue 实现简单的时间轴 时间进度条

项目需要按天播放地图等值线图功能&#xff0c;所以需要一个时间进度条&#xff0c;网上找了一下发现没有自己需要的样子&#xff0c;于是只能简单的写一个。 1、封装时间尺度组件 <!-- 时间尺度 --> <template><div class"time"><div class&…

vue动态改变元素样式详解

目录1 前言2 动态改变样式的方法2.1 操作元素class列表2.2 操作元素内联样式3 小结1 前言 在vue项目中&#xff0c;很多场景要求我们动态改变元素的样式&#xff0c;比如按钮由不可点击到可以点击样式改变&#xff0c;这种情况下&#xff0c;我们通常根据vue框架提供的动态绑定…

vue3的ref,reactive的使用和原理解析

目录 1.前言 2.比较 3.ref源码解析 4.reactive源码解析 createReactiveObject handles的组成 get陷阱 set陷阱 5.总结 1.前言 vue3新增了ref&#xff0c;reactive两个api用于响应式数据&#xff0c;Ref 系列毫无疑问是使用频率最高的 api 之一,响应式意味着数据变动&…

前端get/post等请求后,一直处于pending状态,解决办法

前端发送完请求发现network里的请求一直处于pending状态&#xff08;如图&#xff09; 或者等待过一段事件后会报错&#xff0c;如图 然后我尝试了一些解决办法&#xff0c;分享给大家&#xff0c;建议大家按照顺序来 1.首先排查是不是后端的问题 这个最重要&#xff0c;不然搞…

Vue3-使用axios发起网络请求

即使是小型项目也会涉及到请求后端API&#xff0c;除非你的网站展示的是一些不需要维护的静态数据&#xff0c;第三篇文章我们来给Vue项目搞上axios。 何为Axios &#xff1f;请看官方对Axios的描述&#xff0c;传送门:官方文档 Axios 是一个基于 promise 网络请求库&#xff0…

vue项目中使用md5加密、crypto-js加密、国密sm3、国密sm4

项目中涉及到一些加密解密的需求&#xff0c;了解并尝试了几种加密解密方法&#xff0c;以下&#xff1a; 方法一&#xff1a;md5加密 注意&#xff1a;md5的特性就是只能加密&#xff0c;所以用md5加密的时候&#xff0c;一定要记住你填写的内容&#xff0c;因为它是无法解密…

Vue el-menu-item实现路由跳转

场景&#xff1a;用了element-ui的el-menu 菜单 怎样实现路由跳转呢&#xff1f; 1&#xff0c;在el-menu加上router&#xff0c;添加el-menu的default-active属性&#xff0c;加&#xff1a;动态绑定&#xff0c;值设置为"this.$router.path" &#xff0c; 2&#x…

解决跨域Access to XMLHttpRequest at ‘http://localhost:8080/xxx’ from origin ‘http://localhost:63342

这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注…

web前端-JavaScript中的forEach和map方法

&#x1f41a;作者简介&#xff1a;苏凉&#xff08;专注于网络爬虫&#xff0c;数据分析&#xff0c;正在学习前端的路上&#xff09; &#x1f433;博客主页&#xff1a;苏凉.py的博客 &#x1f310;系列总专栏&#xff1a;web前端基础教程 &#x1f451;名言警句&#xff1a…

vue项目,如何关闭eslint检测?多种解决办法

新版本vue项目&#xff0c;如何关闭eslint检测一、问题描述二、问题解决1、首先是比较旧的vue项目2、创建项目的时候&#xff0c;不要选eslint3、如果你使用的编辑软件是webstorm4、创建的项目没有webpack.base.conf.js文件&#xff0c;但是有 .eslintrc.js5、比较新的vue项目&…

vue3获取元素并修改元素样式

&#x1f525;&#x1f525;&#x1f525;欢迎关注csdn前端领域博主: 前端小王hs &#x1f525;&#x1f525;&#x1f525;email: 337674757qq.com &#x1f525;&#x1f525;&#x1f525;前端交流群&#xff1a; 598778642 需求&#xff1a;获取元素的样式并且修改元素样式…

猿创征文|我的前端学习之旅【来自一名大四老学长的真情流露】

猿创征文 | 我的前端学习之旅自我介绍我浑噩的大一大二&#xff08;是不是另一个你&#xff09;我的大三生活大三上&#xff08;学习过程、学习方法、推荐网站&#xff09;大三下&#xff08;技术提升、荣誉证书、推荐比赛&#xff09;我与 CSDN 的机缘&#xff08;从小白到创作…

【微信小程序】视图容器和基本内容组件

开发者可以通过运用组件快速搭建出页面结构&#xff0c;上一章也有对组件进行介绍&#xff0c;那么本文牛牛就来带大家学习小程序的组件。 我们可以将组件理解为微信内嵌的标签&#xff0c;它在小程序承担的作用与HTML的标签一致&#xff0c;不过组件的功能更加多样、具体。 事…

如何在UNI-APP内开发微信公众号(H5)JSSDK

参考文章 UNI-APP 开发微信公众号&#xff08;H5&#xff09;JSSDK 的使用方式 微信内H5使用JSSDK分享&#xff01;&#xff01;&#xff01;注意目前Hbuilderx2.3.7版本存在问题&#xff01;&#xff01;&#xff01; vue-router与location.href的用法区别 微信网页开发 JSSDK…

近四十场面试汇聚成的超全Web服务器面经总结

上期写了简历项目链接简历项目烂大街怎么办&#xff1f;教你最有谱的摆烂&#xff0c;有位读者照做以后&#xff0c;拿下了主管面&#xff0c;在群里宣传以后&#xff0c;最近多了不少小伙伴来催我更新服务器项目相关知识点。 这份总结是我之前秋招的时候&#xff0c;根据每次…

JS的事件介绍

JS的事件介绍 JS&#xff08;JavaScript&#xff09;是基于对象&#xff08;Object-based&#xff09;、事件驱动的脚本语言。 JS事件&#xff0c;就是用户或浏览器本身的某种行为&#xff0c;一般是用户对页面的一些动作引起的&#xff0c;例如&#xff0c;单击某个链接或按…

分享5款实用且免费的软件,让你轻松地完成任务

在日常工作和生活中&#xff0c;使用一些实用的小巧工具软件可以提高效率&#xff0c;让你更轻松地完成任务。 1.图像编辑——Paint.NET Paint.NET是一款免费的图像编辑软件&#xff0c;具有多种高级功能和插件支持。它支持多种文件格式、层、魔术棒、文本、画笔、形状、调整…