目录
后端设置
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
函数负责处理错误,并向用户显示相关的错误消息。
通过依赖 和 配置 生效