- 單點登錄的三種常見方法
- session廣播機制(不常用)
- 通過session登錄之后,將session的值復制到每個模塊中
- cookies和redis實作
- 在任意一個模塊進行登錄,登錄之后將登錄資料存到兩個地方
- redis:key生成唯一隨機值,value是用戶資料
- cookie:把redis生成的key值存放到cookie中
- 訪問專案模塊時,需要帶著cookie發送請求,根據請求帶來的cookie到redis查詢,查詢即表示登錄
- 在任意一個模塊進行登錄,登錄之后將登錄資料存到兩個地方
- token實作(令牌機制)
- token表示按照一定的規則(通用的、官方的,如JWT)生成的字串(可以包含用戶的資訊)
- jwt頭部資訊
- 有效載荷,包含用戶主體資訊
- 簽名哈希,防偽標志
- 在任意一個模塊進行登錄,登錄之后按照一定的規則將登錄之后的用戶資料生成字串,通過兩種方法方式回傳
- 可以把字串通過cookie回傳
- 把字串加到地址欄回傳
- 訪問專案模塊時,地址欄需要帶著生成的字串發送請求,根據字串獲取用戶資訊,獲取成功即表示登錄
- 匯入依賴
<!-- JWT --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.7.0</version> </dependency> - JWT工具類(內容較為為固定,易知放在公共模塊中)
package com.atguigu.commonutils; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jws; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.util.StringUtils; import javax.servlet.http.HttpServletRequest; import java.util.Date; public class JwtUtils { // token過期時間 public static final long EXPIRE = 1000 * 60 * 60 * 24; // 密鑰(隨意寫,企業中有規定的字串) public static final String APP_SECRET = "ukc8BDbRigUDaY6pZFfWus2jZWLPHO"; // 生成token字串的方法 public static String getJwtToken(String id, String nickname){ String JwtToken = Jwts.builder() // 設定頭部引數 .setHeaderParam("typ", "JWT") .setHeaderParam("alg", "HS256") // 設定分類以及過期時間 .setSubject("guli-user") .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() + EXPIRE)) // 設定token主體部分,存盤用戶資訊,不限個數(屬性) .claim("id", id) .claim("nickname", nickname) // 設定簽名哈希,防偽標志 .signWith(SignatureAlgorithm.HS256, APP_SECRET) .compact(); return JwtToken; } /** * 判斷token是否存在與有效 * @param: jwtToken * @return */ public static boolean checkToken(String jwtToken) { if(StringUtils.isEmpty(jwtToken)) return false; try { Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken); } catch (Exception e) { e.printStackTrace(); return false; } return true; } /** * 判斷token是否存在與有效 * @param request * @return */ public static boolean checkToken(HttpServletRequest request) { try { String jwtToken = request.getHeader("token"); if(StringUtils.isEmpty(jwtToken)) return false; Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken); } catch (Exception e) { e.printStackTrace(); return false; } return true; } /** * 根據token獲取會員id * @param request * @return */ public static String getMemberIdByJwtToken(HttpServletRequest request) { String jwtToken = request.getHeader("token"); if(StringUtils.isEmpty(jwtToken)) return ""; Jws<Claims> claimsJws = Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken); Claims claims = claimsJws.getBody(); // 和上面的設定主體部分屬性名稱一樣即可,獲取什么可根據需求 return (String)claims.get("id"); } } - 注冊時,填寫相關資訊,獲取驗證碼呼叫介面的業務代碼(可參考博主的“SpringBoot整合阿里云短信服務”)
- 登錄成功時需要回傳按照JWT(JWT工具類)規則生成的token字串的業務代碼(其中需求可改)
@Override public String userLogin(UcenterMember member) throws MyException { String mobile = member.getMobile(); String password = member.getPassword(); // 手機號和密碼是否為空 if(StringUtils.isEmpty(mobile) || StringUtils.isEmpty(password)) { throw new MyException(20001, "登錄失敗!"); } // 判斷手機號是否正確 QueryWrapper<UcenterMember> wrapper = new QueryWrapper<>(); wrapper.eq("mobile", mobile); UcenterMember ucenterMember = this.getOne(wrapper); if(ucenterMember == null) { throw new MyException(20001, "手機號錯誤!"); } // 判斷密碼是否正確 // 將輸入密碼加密與資料庫校驗(每個企業的加密方式不一樣) if(!MD5.encrypt(password).equals(ucenterMember.getPassword())) { throw new MyException(20001, "密碼錯誤!"); } // 判斷用戶的狀態(禁用 or 活躍) if(ucenterMember.getIsDisabled()) { throw new MyException(20001, "登錄失敗!"); } // 按照JWT的規則生成token字串 String id = ucenterMember.getId(); String nickname = ucenterMember.getNickname(); String token = JwtUtils.getJwtToken(id, nickname); return token; } - 前端發送請求時將token帶回來進行決議(JWT工具類中已有決議token的方法)獲取其中的用戶主題資訊,回傳用戶的資訊給前端,
// 根據token獲取用戶資訊 @GetMapping("getMemberInfo") public R getMemberInfo(HttpServletRequest request) { // 呼叫jwt工具類的方法,根據request物件獲取頭資訊,回傳用戶id String memberId = JwtUtils.getMemberIdByJwtToken(request); // 查詢資料庫根據用戶id獲取用戶資訊 UcenterMember member = memberService.getById(memberId); return R.ok().data("memberInfo", member); } - 接下來單點登錄的重頭戲,vue先下載js-cookie(前端代碼)
- 上面登錄成功時回傳的token字串,前端將token字串放到cookie里面
//第二步 獲取token字串放到cookie里面 //第一個引數cookie名稱,第二個引數值,第三個引數作用范圍 cookie.set('guli_token',response.data.data.token,{domain: 'localhost'}) - 創建前端攔截器,判斷cookie里面是否有token字串,如果有,就將token字串放到header(請求頭)中
import axios from 'axios'; import cookie from 'js-cookie'; // 創建axios實體 const service = axios.create({ baseURL: 'http://localhost:9001', // api的base_url timeout: 20000 // 請求超時時間 }); //第三步 創建攔截器 http request 攔截器 service.interceptors.request.use( config => { //debugger //判斷cookie里面是否有名稱是guli_token資料 if (cookie.get('guli_token')) { //把獲取cookie值放到header里面 config.headers['token'] = cookie.get('guli_token'); } return config }, err => { return Promise.reject(err); }); - 根據token值呼叫相關的介面,根據token獲取用戶資訊,將回傳的用戶資訊放到cookie中,為了顯示頁面(主頁)
//第四步 呼叫介面 根據token獲取用戶資訊,為了首頁面顯示 loginApi.getLoginUserInfo() .then(response => { this.loginInfo = response.data.data.memberInfo //獲取回傳用戶資訊,放到cookie里面 cookie.set('guli_ucenter',this.loginInfo,{domain: 'localhost'}) //跳轉頁面 window.location.href = "https://www.cnblogs.com/"; }) - 完整的代碼大致如下
//登錄的方法 submitLogin() { //第一步 呼叫介面進行登錄,回傳token字串 loginApi.submitLoginUser(this.user) .then(response => { //第二步 獲取token字串放到cookie里面 //第一個引數cookie名稱,第二個引數值,第三個引數作用范圍 cookie.set('guli_token',response.data.data.token,{domain: 'localhost'}) //第四步 呼叫介面 根據token獲取用戶資訊,為了首頁面顯示 loginApi.getLoginUserInfo() .then(response => { // 一定要在這里轉成字串 this.loginInfo = JSON.stringify(response.data.data.memberInfo); //獲取回傳用戶資訊,放到cookie里面 cookie.set('guli_ucenter',this.loginInfo,{domain: 'localhost'}) //跳轉頁面 window.location.href = "https://www.cnblogs.com/"; }) }) } - 從cookie的獲取資料顯示到頁面中
var user = "cookie中存放用戶的資訊(上面將json格式轉成了字串型別)" // 將資訊顯示到頁面中 this.userInfo = JSON.parse(user);
- 上面登錄成功時回傳的token字串,前端將token字串放到cookie里面
- token表示按照一定的規則(通用的、官方的,如JWT)生成的字串(可以包含用戶的資訊)
- session廣播機制(不常用)
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/438003.html
標籤:Java
上一篇:Redis基本操作
下一篇:Android 面試知識總結
