原文:juejin.cn/post/7025768845075808286
前言
本文通過圖示及代碼的方式介紹用戶登錄流程及技術實作,內容包括用戶登錄,用戶驗證,如何獲取操作用戶的資訊以及一些黑名單及匿名介面如何免驗證相關的實作,
業務圖解
對于用戶登錄來說、涉及到了用戶注冊、登錄驗證幾個方面,通過流程圖演示如何處理(新用戶/老用戶)登錄

流程解讀
客戶端-登錄界面(通常手機驗證碼登錄)
- 填寫手機號
- 發送驗證碼
- 填寫驗證碼
- 勾選新用戶自動注冊
服務端-用戶驗證
- 驗證賬號驗證碼是否正確
- 驗證用戶是否存在(不存在出初始化用戶資訊)
- 完成驗證生成token
- 將token回傳給客戶端
用戶資訊設計

驗證流程圖解

登錄驗證流程涉及到了兩個介面,兩個快取,
- 獲取驗證碼介面,給手機號發送驗證碼并設定驗證碼快取,設定過期時間;
- 登錄介面,提交手機號及驗證碼,讀取快取進行匹配驗證,成功則生成token回傳給客戶端,客戶端登錄成功,登錄后請求頭攜帶token進行業務請求即可,
關于token過期時間
通常我們token的過期時間是根據客戶端的型別來定義的,app的過期時間會更長一些(通常一個星期),web端過期時間以小時為單位,如果控制過期時間可以將web登錄和app登錄拆分為兩個介面(能夠分流,介面壓力更小),或者是根據請求頭資訊進行判斷即可,是移動端就設定7天,是web端就設定兩小時,
關于業務請求token驗證
登錄成功后,客戶端每次請求都會攜帶token,通常我們會有一個網關來進行token驗證,網關用于登錄驗證的核心就是登錄成功后寫入的token作為key,值為用戶基礎資訊的快取,圖解如下:

驗證成功后,重寫內部請求頭,將用戶的的id,賬號,昵稱資訊放入請求頭中,這樣可以方便業務系統獲取當前操作用戶資訊以及權限控制等等
關于登出操作
用戶攜帶token請求登出介面,登出介面對token對應的快取進行洗掉操作,回傳401即可,客戶端獲取到401就會跳轉到登錄頁面
關于匿名請求(免登錄)
通常匿名請求放行有兩種方案,
- 授權token,為token設定單位時間內請求次數;
- 配置路徑放行規則,對請求介面路徑進行正則匹配,符合正則規則的進行放行
方案1:授權token,限制單位時間請求次數
優點就是雖然是免登錄介面,但是介面的操作物件可以追溯,請求次數可控,避免被非法利用;缺點就是需要更多的編碼及配置作業
技術實作
- 提供一個授權token管理頁面,主要管理token使用者,token的值,單位時間訪問次數(如每分鐘60次)
- 增刪改查,將授權token存放到快取中,使用map進行存盤,key為token,值為每分鐘訪問次數
- 單位時間計數快取,過期時間為1分鐘
這時候我們需要在上面的驗證流程圖基礎上進行升級

請求次數檢查代碼實作
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
/**
* 授權token請求限制快取
*/
@Component
public class AuthTokenRequestLimitCache {
@Autowired
private RedisTemplate<String, Integer> redisTemplate;
private static final String AUTH_TOKEN_LIMIT_KEY_PREFIX = "auth_token_limit";
/**
* 請求次數+1并檢查是否超限
*
* @param token
* @return 是否放行
*/
public boolean incrementWithCheck(String token) {
// 1.獲取token請求次數限制,獲取為null代表授權配置已被修改,此token已經不具備權限
Integer limit = getLimit(token);
if (limit == null) {
return false;
}
// 2.組裝快取key,讀取快取
String key = String.join(":", AUTH_TOKEN_LIMIT_KEY_PREFIX, token);
Integer count = redisTemplate.opsForValue().get(key);
// 3.沒有值代表一分鐘內沒有請求產生了
if (count == null) {
// 初始化值
redisTemplate.opsForValue().increment(key);
// 設定過期時間
redisTemplate.expire(key, 1L, TimeUnit.MINUTES);
return true;
}
// 自增并獲取當前值 大于限制的話 回傳false 網關過濾器回傳提示資訊(如請求過于頻繁)
Long inc = redisTemplate.opsForValue().increment(key);
return inc <= limit;
}
/**
* 獲取限值
*
* @param token
* @return
*/
public Integer getLimit(String token) {
Object limit = redisTemplate.opsForHash().get("auth_token_limit", token);
return limit == null ? null : (Integer) limit;
}
}
對于授權介面,通常是只允許get操作,對資料進行提交或者更新是不被允許的,當然這個是業務層面的,最終取決于系統設計
方案2:請求路徑正則校驗
我們在網關的組態檔中增加匿名介面規則,請求到網關時,檢查請求的路徑是否符合匿名介面規則,是則放行,不是則進行token校驗,方案比較簡單,只需要對網關進行處理即可,
關于黑名單
對于一個系統來說,黑名單是最后一道關卡,所以為了安全我們需要對問題用戶進行黑名單操作,具體實作也比較簡單
- 用戶管理頁面提供一個拉黑的按鈕,拉黑后,這些用戶的id會存盤到一個set集合中去
- 登錄時候檢查用戶是否在黑名單中,是則拒絕登錄并提示
- 如果用戶已經登錄后進行拉黑操作,網關會在鑒權通過后檢查用戶是否在黑名單中,是則洗掉token對應快取,回傳401,401就會跳到登錄頁,步驟2就會進行攔截,
總結
用戶系統是非常基礎的系統,但是很多程式員作業中可能并沒有真正的參與到用戶系統的開發,通過此文可以對用戶登錄流程及配套功能有一個全面的了解,
近期熱文推薦:
1.1,000+ 道 Java面試題及答案整理(2022最新版)
2.勁爆!Java 協程要來了,,,
3.Spring Boot 2.x 教程,太全了!
4.別再寫滿屏的爆爆爆炸類了,試試裝飾器模式,這才是優雅的方式!!
5.《Java開發手冊(嵩山版)》最新發布,速速下載!
覺得不錯,別忘了隨手點贊+轉發哦!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/500336.html
標籤:其他
