目錄
后端設置
Controller 層
Service 層
后端返回 Token 給前端
1. 用戶提交登錄請求
2. 后端驗證用戶身份
3. 返回 Token
4. 前端保存 Token
前端存儲
1. 前端向后端發起請求
2. 前端存儲一下 Token
3.管理用戶認證的 token 的 工具
4. 在 Service 層進行設置 HTTP 請求工具
后端設置
Controller 層
/*** 用戶登錄** @param login 登錄參數* @return {@link String} Token*/@ApiOperation(value = "用戶登錄")@PostMapping("/login")public Result<String> login(@Validated @RequestBody LoginReq login) {return Result.success(loginService.login(login));}
Service 層
首先用 userMapper 查詢數據庫中的數據是否存在
User user = userMapper.selectOne(new LambdaQueryWrapper<User>().select(User::getId).eq(User::getUsername, login.getUsername()).eq(User::getPassword, SecurityUtils.sha256Encrypt(login.getPassword())));
再標記當前登錄賬號 id
// 標記當前會話登錄的賬號id
StpUtil.login(user.getId());
返回 Token 數值
return StpUtil.getTokenValue();
全部代碼
public String login(LoginReq login) {try {User user = userMapper.selectOne(new LambdaQueryWrapper<User>().select(User::getId).eq(User::getUsername, login.getUsername()).eq(User::getPassword, SecurityUtils.sha256Encrypt(login.getPassword())));Assert.notNull(user, "用戶不存在或密碼錯誤");// 校驗指定賬號是否已被封禁,如果被封禁則拋出異常 `DisableServiceException`StpUtil.checkDisable(user.getId());// 通過校驗后,再進行登錄// 標記當前會話登錄的賬號idStpUtil.login(user.getId());// 拿到當前登錄賬號的IdInteger userId = StpUtil.getLoginIdAsInt();System.out.println("當前登錄賬號的Id: "+userId);String token = StpUtil.getTokenValue(); // 獲取當前線程的 tokenSystem.out.println("Token: " + token); // 打印出 token 以便調試// //獲取當前是否登錄
// StpUtil.isLogin();System.out.println("登錄狀態: "+StpUtil.isLogin());
// //檢驗當前會話是否已經登錄
// StpUtil.checkLogin();return StpUtil.getTokenValue();} catch (IllegalArgumentException e) {e.printStackTrace();throw e;}}
后端返回 Token 給前端
后端登錄成功后,通常會將一個 Token 返回給前端,這個 Token 通常是一個 JWT(JSON Web Token),它包含了用戶身份和一些其他的認證信息,并且可以用來進行后續的 API 請求驗證。后端返回 Token 的過程通常是這樣的:
1. 用戶提交登錄請求
用戶輸入用戶名和密碼后,前端會將請求發送到后端,后端會進行認證。
2. 后端驗證用戶身份
后端會根據用戶名和密碼進行身份驗證,如果驗證成功,則生成一個 Token,通常是 JWT 格式。
3. 返回 Token
后端將 Token 返回給前端,前端可以在后續的請求中將這個 Token 放在請求頭中(通常是 Authorization: Bearer token)來進行身份認證。
4. 前端保存 Token
前端通常會把 Token 保存在瀏覽器的 localStorage 或 sessionStorage 中,或者通過 HTTP-only 的 cookie 來存儲,以便在之后的請求中攜帶。
前端存儲
把 表單里面的數據 作為參數
1. 前端向后端發起請求
異步請求
login(loginForm.value).then(({ data }) => {if (data.flag) {setToken(data.data);// user.GetUserInfo();window.$message?.success("登錄成功");loginForm.value = {username: "",password: "",};app.setLoginFlag(false);}loading.value = false;});
2. 前端存儲一下 Token
setToken(data.data);
3.管理用戶認證的 token 的 工具
寫一個管理用戶認證的 token 的 TypeScript 代碼
import Cookies from "js-cookie";const TokenKey: string = "Token";// 我網站的域名是www.ttkwsd.top,去前面的www,改成自己的域名
const domain: string = ".gczdy.cn";// token前綴
export let token_prefix = "Bearer ";export function getToken() {return Cookies.get(TokenKey);
}// 本地運行記得刪除domain
export function setToken(token: string) {// 項目線上部署可以取消注釋// return Cookies.set(TokenKey, token, { domain: domain });return Cookies.set(TokenKey, token);
}export function removeToken() {// 項目線上部署可以取消注釋// return Cookies.remove(TokenKey, { domain: domain });return Cookies.remove(TokenKey);
}
這段代碼是用來管理用戶認證的 token(令牌)的,通常用于前端應用中的身份驗證部分。它使用了 js-cookie
庫來處理 cookies 的操作。下面逐行解釋:
1. import Cookies from "js-cookie";
- 導入
js-cookie
庫,它是一個簡化操作 cookies 的 JavaScript 庫。通過它可以方便地存儲、獲取和刪除 cookies。
2. const TokenKey: string = "Token";
- 定義了一個常量
TokenKey
,值為"Token"
,作為存儲 token 的 cookie 鍵名。這個鍵用于在 cookies 中存取用戶的 token。
3. const domain: string = ".gczdy.cn";
- 定義了一個
domain
常量,表示 cookies 適用的域名。.gczdy.cn
是設置 cookies 時的域名,意味著該 cookie 會對該域及其子域名(例如www.gczdy.cn
或app.gczdy.cn
)有效。 - 代碼中也有注釋提到:如果是本地開發環境,可以刪除該行。
4. export let token_prefix = "Bearer ";
- 定義了一個
token_prefix
常量,表示 token 的前綴。通常在 HTTP 請求中,token 會與前綴(如 "Bearer ")一起發送,以標明它是一個授權令牌。 - 例如,使用 token 時會變成
Bearer <token_value>
。
5. export function getToken() { return Cookies.get(TokenKey); }
- 定義了一個
getToken
函數,用來獲取存儲在 cookies 中的 token。它通過Cookies.get()
方法使用TokenKey
獲取相應的 token 值。
6. export function setToken(token: string) { return Cookies.set(TokenKey, token); }
- 定義了一個
setToken
函數,用來將 token 存儲到 cookies 中。它使用Cookies.set()
方法,將傳入的token
存儲到 cookies 中,鍵名是TokenKey
。 - 如果是線上環境,可以啟用注釋中的
domain
設置,將 cookie 限定在特定域名下。
7. export function removeToken() { return Cookies.remove(TokenKey); }
- 定義了一個
removeToken
函數,用來刪除存儲在 cookies 中的 token。它通過Cookies.remove()
方法,刪除了鍵名為TokenKey
的 cookie。
總結:
- 這段代碼主要用來操作用戶的認證信息(token)。它提供了三個函數:
-
getToken()
用來獲取存儲的 token;setToken(token)
用來將 token 存儲到 cookies 中;removeToken()
用來刪除存儲的 token。
- 這些操作通常用于前端應用中的登錄認證流程。存儲 token 可以用于后續的 API 請求(例如,通過在請求頭中添加
Authorization: Bearer <token>
來驗證用戶身份)。
4. 在 Service 層進行設置 HTTP 請求工具
import { getServiceBaseURL } from "@/utils/service";
import { getToken, token_prefix } from "@/utils/token";
import { createRequest } from "./request";
const isHttpProxy =import.meta.env.DEV && import.meta.env.VITE_HTTP_PROXY === "Y";
const { baseURL } = getServiceBaseURL(import.meta.env, isHttpProxy);export const request = createRequest<App.Service.Response>({baseURL,},{async onRequest(config) {// 請求帶tokenif (getToken()) {// Authorization -> satokenconfig.headers["Authorization"] = token_prefix + getToken();}return config;},isBackendSuccess(response) {return response.data.code === 200;},async onBackendFail(_response) {},transformBackendResponse(response) {return response.data.data;},onError(error) {let message = error.message;if (error.code === "BACKEND_ERROR_CODE") {message = error.response?.data?.msg || message;}window.$message?.error(message);},}
);
之后在發請求的時候 前端會把這個 Token 放到 Header 里面
帶給后端
這段代碼主要用于創建一個 HTTP 請求工具,通常用于前端應用中處理與后端的通信。它使用了封裝的 createRequest
函數來生成請求實例,并配置了多個鉤子函數來處理請求、響應和錯誤等。下面是逐行解釋:
1. import { getServiceBaseURL } from "@/utils/service";
- 從
@/utils/service
模塊導入getServiceBaseURL
函數。這個函數通常用于根據環境配置(如開發、生產)來獲取服務的基本 URL。
2. import { getToken, token_prefix } from "@/utils/token";
- 從
@/utils/token
模塊導入getToken
和token_prefix
。getToken
用來獲取存儲在 cookies 中的用戶 token,token_prefix
是 token 的前綴(通常為 "Bearer ")。
3. import { createRequest } from "./request";
- 從本地的
request
模塊導入createRequest
函數。createRequest
用于創建一個 HTTP 請求實例,并可以配置請求的一些默認行為。
4. const isHttpProxy = import.meta.env.DEV && import.meta.env.VITE_HTTP_PROXY === "Y";
- 定義了一個
isHttpProxy
變量,判斷當前是否在開發環境(import.meta.env.DEV
)以及是否啟用了 HTTP 代理(import.meta.env.VITE_HTTP_PROXY
)。這通常用于調試或跨域請求代理。
5. const { baseURL } = getServiceBaseURL(import.meta.env, isHttpProxy);
- 調用
getServiceBaseURL
函數,傳遞環境配置(import.meta.env
)和isHttpProxy
參數,獲取服務的基礎 URL。baseURL
將作為請求的基礎地址。
6. export const request = createRequest<App.Service.Response>( { baseURL }, { ... });
- 使用
createRequest
函數創建一個請求實例,傳入配置項。其中baseURL
是請求的基礎 URL,后面的對象是配置該請求的具體行為。 App.Service.Response
表示請求響應的類型,確保請求和響應數據的類型安全。
7. async onRequest(config) { ... }
onRequest
是請求鉤子函數,在每個請求發送之前執行。它可以用來修改請求的配置。- 這里檢查
getToken()
是否存在,如果存在則在請求頭中添加Authorization
字段,值為Bearer <token>
,用于身份驗證。
8. isBackendSuccess(response) { return response.data.code === 200; }
isBackendSuccess
是用來判斷后端響應是否表示請求成功。根據響應中的data.code
是否等于 200 來判斷。
9. async onBackendFail(_response) { ... }
onBackendFail
是當后端返回失敗時觸發的回調函數。在這個示例中,沒有任何具體的邏輯實現,可能是保留的空函數,或者在后端失敗時要進行的其他處理。
10. transformBackendResponse(response) { return response.data.data; }
transformBackendResponse
用于處理從后端響應的數據。默認從響應中提取data.data
部分,作為最終返回的數據。這樣可以統一處理不同后端返回的數據格式。
11. onError(error) { ... }
onError
是請求發生錯誤時的回調函數。在這里,錯誤消息會根據error.code
來定制,如果錯誤類型是BACKEND_ERROR_CODE
,則從響應中提取錯誤信息。最后,使用window.$message?.error(message)
顯示錯誤信息。
總結:
- 這段代碼定義了一個
request
實例,用于執行 API 請求。它封裝了請求配置、響應處理、錯誤處理等多個方面的邏輯。 onRequest
鉤子在請求發送前自動添加 token,用于授權。isBackendSuccess
函數用來判斷后端是否成功處理了請求。transformBackendResponse
用于提取后端響應數據的有效部分。onError
函數負責處理錯誤,并向用戶顯示相關的錯誤消息。
通過依賴 和 配置 生效