Java中token的存儲(chǔ)和獲取實(shí)例代碼
1. 獲取token的工具類
問(wèn):為什么寫工具類呢???
答:因?yàn)槲覀儾恢狼岸藢oken怎么存儲(chǔ)的,所以我們可以通過(guò)調(diào)用Token工具類來(lái)獲取token。Token工具類會(huì)檢查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存儲(chǔ)token
2.1 前端存儲(chǔ)token
第一步安裝:js-cookie
npm install --save js-cookie
第二步引入:(這里以vue開(kāi)發(fā)為例,在main.js中引入?。?/p>
// 全局應(yīng)用Cookie import Cookie from 'js-cookie' Vue.prototype.$Cookie = Cookie
第三步:前端訪問(wèn)后端,得到token后進(jìn)行存儲(chǔ)。
// 向后端發(fā)送登錄請(qǐng)求 this.axios({ method: "post", headers: { // 測(cè)試header保存數(shù)據(jù) "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); //根據(jù)后端返回的狀態(tài)查看賬號(hào)是否正確 if (res.data.code == 0) { // =============== cookie的操作 ================ // 博文: https://blog.csdn.net/qq_16828495/article/details/120783389 // 保存token that.$Cookie.set("token", res.data.data.token); //登錄成功后跳轉(zhuǎn)到后臺(tái)的個(gè)人信息界面 that.$message.success("登錄成功!"); that.$router.push({path: "/userInfo"}); } else { that.$message.error(res.data.message); } }) .catch(err => { // 后端如果出現(xiàn)異常,前端會(huì)報(bào)401錯(cuò)誤。 這里捕獲401錯(cuò)誤。 //console.log(err.response.data) if (err.response != null) { this.$message.error(err.response.data.message); } else { this.$message.error("未知異常"); } })
2.2 訪問(wèn)攜帶token
axios({ method: "get", headers: { // 傳輸token用于驗(yàn)證當(dāng)前登錄用戶 "token": that.$Cookie.get("token"), }, url: "http://" + that.$store.state.host + "/zm-task/login/updateEmail", params:{ // 需要修改的郵箱屬性 "email": formName.email } }).then(res => { // 直接顯示后端傳來(lái)的信息 that.$message.success(res.data.message); }).catch(err => { // 后端如果出現(xiàn)異常,前端會(huì)報(bào)401錯(cuò)誤。 這里捕獲401錯(cuò)誤。 if (err.response != null) { this.$message.error(err.response.data.message); } else { this.$message.error("未知異常"); } })
2.3 后端獲取token并進(jìn)行驗(yàn)證(攔截器中進(jìn)行驗(yàn)證)
@Slf4j public class UserLoginAuthInterceptor implements HandlerInterceptor { /** * * @param request : 請(qǐng)求(通過(guò)請(qǐng)求獲取token登陸憑證) * @param response : 返回給前端的響應(yīng) * @param handler : 該參數(shù)中包含了對(duì)應(yīng)方法的信息。比如:方法中的參數(shù)類型、參數(shù)的注解、方法的注解等信息。 * @return * @throws Exception : 向上拋出異常 */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 排除資源請(qǐng)求 if (!(handler instanceof HandlerMethod)) { return true; } // 通過(guò)handler獲取方法上面的Login注解 HandlerMethod handlerMethod = (HandlerMethod) handler; Login login = handlerMethod.getMethod().getAnnotation(Login.class); //說(shuō)明方法上面沒(méi)有Login注解 if (login == null){ return true; } // 有Login注解,但是Login的屬性值為false if (Boolean.FALSE.equals(login.loginRequired())){ return true; } // 獲取請(qǐng)求頭中的token請(qǐng)求 String token = request.getHeader("token"); // 根據(jù)token獲取登陸的用戶信息(登陸賬號(hào), 登陸ip, 用戶權(quán)限0、1、2) UserLoginModel userLoginModel = JWTUtil.tokenToUser(token, request); // 獲取當(dāng)前請(qǐng)求的ip地址?。?! (公網(wǎng)才有效果) 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); } // 這里只有線上測(cè)試才能有效果,非線上測(cè)試無(wú)效果! (ipAddr公網(wǎng)才能獲取準(zhǔn)確的IPv4) if (!ipAddr.equals(userLoginModel.getIP())){ // 登陸IP 與 請(qǐng)求IP不相同,所以重新進(jìn)行登陸 log.error("登陸ip:{}, 請(qǐng)求ip:{}", userLoginModel.getIP(), ipAddr); //todo redis保存ip地址,防止被爆刷接口 throw new BizException(ServerEnum.LOGIN_ERROR); } //使用ThreadLocal保存用戶信息 UserLoginInfoThreadLocalUtil.set(userLoginModel); return true; } /** * 在整個(gè)請(qǐng)求處理完畢后進(jìn)行回調(diào),也就是說(shuō)視圖渲染完畢或者調(diào)用方已經(jīng)拿到響應(yīng)。 * @param request * @param response * @param handler * @param ex * @throws Exception */ @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { //防止內(nèi)存泄漏 UserLoginInfoThreadLocalUtil.clear(); } }
3. URL中的屬性值
以這個(gè)地址為例:https://editor.csdn.net/md?articleId=125379150&name=Thomas
當(dāng)進(jìn)行Get
或者Post
請(qǐng)求的時(shí)候,在url后面添加參數(shù)便可以?。?!
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 { //設(shè)置請(qǐng)求編碼格式 request.setCharacterEncoding("UTF-8"); //設(shè)置響應(yīng)編碼格式 response.setCharacterEncoding("UTF-8"); //設(shè)置數(shù)據(jù)返回的類型 response.setContentType("text/json"); // 獲取請(qǐng)求信息(參數(shù)id對(duì)應(yīng)的值) Integer id = Integer.valueOf(request.getParameter("id")); // 原本想獲取請(qǐng)求url中的值,但是無(wú)法通過(guò)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 (說(shuō)明只能獲取路徑?后面的參數(shù),不能獲取包含在路徑中的參數(shù)?。?!) 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();//關(guān)閉流 } // http://localhost:8080/cookie/login/getCookie @GetMapping("/login/getCookie") public void getCookies(HttpServletRequest request, HttpServletResponse response) throws IOException { //設(shè)置數(shù)據(jù)返回的類型 response.setContentType("text/json"); //設(shè)置請(qǐng)求編碼格式 request.setCharacterEncoding("UTF-8"); //設(shè)置響應(yīng)編碼格式 response.setCharacterEncoding("UTF-8"); String State = "fail"; //獲取Cookie信息數(shù)組 Cookie[] cks = request.getCookies(); if (cks != null){ for(Cookie cookie : cks){ System.out.println(cookie.getName() + "=" + cookie.getValue()); } } PrintWriter out=response.getWriter(); out.write("測(cè)試獲取Cookie"); out.flush();//刷新該流的緩沖 out.close();//關(guān)閉流 } }
4.2 測(cè)試 向Cookie中插入key - value值?。?!
之后的Get或者Post請(qǐng)求,不需要我們主動(dòng)去插入cookie,請(qǐng)求會(huì)自動(dòng)攜帶cookie進(jìn)行訪問(wèn)!??!
講解完畢?。?!
注意:
問(wèn)題:因?yàn)楹蠖巳ピO(shè)置Cookie,會(huì)涉及跨域,但是cookie是不能跨域的。這就造成了頁(yè)面跳轉(zhuǎn)時(shí)請(qǐng)求頭帶不上cookie中的token。這時(shí)只要把Domain設(shè)置成.+一級(jí)域名那么就能解決cookie跨域的問(wèn)題了。
Token的使用(兩種方式):
1、 直接返回token字符,讓前端同學(xué)進(jìn)行存儲(chǔ)(Cookie、localStorage、SessionStorage),請(qǐng)求時(shí)候手動(dòng)去攜帶token?。?br />2、 后端同學(xué)設(shè)置cookie的時(shí)候,注意跨域問(wèn)題即可!
總結(jié)
到此這篇關(guān)于Java中token的存儲(chǔ)和獲取的文章就介紹到這了,更多相關(guān)Java存儲(chǔ)和獲取token內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java數(shù)組隊(duì)列及環(huán)形數(shù)組隊(duì)列超詳細(xì)講解
隊(duì)列是一個(gè)有序列表,可以用數(shù)組和鏈表來(lái)實(shí)現(xiàn),隊(duì)列有一個(gè)原則。即:先存入隊(duì)列的數(shù)據(jù)要先取出,后存入的要后取出,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧2022-09-09JAVA實(shí)現(xiàn)Date日期加一天具體方法
這篇文章主要給大家介紹了關(guān)于JAVA實(shí)現(xiàn)Date日期加一天的相關(guān)資料,因?yàn)樵陧?xiàng)目中遇到了需要將日期進(jìn)行加減一些天數(shù)的操作,文中給出了簡(jiǎn)單的代碼示例,需要的朋友可以參考下2023-07-07使用SpringMVC的@Validated注解驗(yàn)證的實(shí)現(xiàn)
這篇文章主要介紹了使用SpringMVC的@Validated注解驗(yàn)證的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08Java的Lambda表達(dá)式和Stream流的作用以及示例
這篇文章主要介紹了Java的Lambda表達(dá)式和Stream流簡(jiǎn)單示例,Lambda允許把函數(shù)作為一個(gè)方法的參數(shù),使用Lambda表達(dá)式可以寫出更簡(jiǎn)潔、更靈活的代碼,而其作為一種更緊湊的代碼風(fēng)格,使Java的語(yǔ)言表達(dá)能力得到了提升,需要的朋友可以參考下2023-05-05Springboot集成mybatis實(shí)現(xiàn)多數(shù)據(jù)源配置詳解流程
在日常開(kāi)發(fā)中,若遇到多個(gè)數(shù)據(jù)源的需求,怎么辦呢?通過(guò)springboot集成mybatis實(shí)現(xiàn)多數(shù)據(jù)源配置,簡(jiǎn)單嘗試一下,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06Java 數(shù)組ArrayList常用語(yǔ)法詳解
這篇文章主要介紹了Java 數(shù)組ArrayList常用語(yǔ)法詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-09-09

Spring擴(kuò)展BeanFactoryPostProcessor使用技巧詳解

MybatisPlus特殊查詢的實(shí)現(xiàn)介紹