本文档记录用户认证、登录、用户信息管理等相关 API 接口。
依赖文档: 请先阅读 API 文档基础规范.md 了解通用规范。
接口地址: POST /auth/login
接口描述: 用户登录认证接口,支持密码登录。请求数据使用 AES+RSA 混合加密传输,确保安全性。
权限要求: 无需认证(公开接口)
安全机制:
请求头配置:
{
"Content-Type": "application/json;charset=utf-8",
"clientid": "e5cd7e4891bf95d1d19206ce24a7b32e",
"encrypt-key": "[RSA加密的AES密钥]",
"referer": "http://localhost/login?redirect=%252Findex",
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
"isToken": "false",
"isEncrypt": "true",
"repeatSubmit": "false"
}
关键请求头说明:
| 请求头名 | 必填 | 说明 | 示例值 |
|---|---|---|---|
| clientid | 是 | 客户端 ID,用于身份验证 | "e5cd7e4891" |
| encrypt-key | 是 | RSA 加密的 AES 密钥,用于数据解密 | "Q8Td0si9R3EYj3pFe50rzn/8wxo69Y9uR6LE..." |
| referer | 是 | 来源页面地址,用于请求来源验证 | "http://localhost/login?redirect=%252Findex" |
加密流程说明:
encrypt-key请求参数:
| 参数名 | 类型 | 必填 | 说明 | 示例值 |
|---|---|---|---|---|
| tenantId | string | 是 | 租户 ID,多租户系统标识 | "000000" |
| username | string | 是 | 用户名,长度 2-30 字符 | "admin" |
| password | string | 是 | 用户密码,长度 5-30 字符 | "admin123" |
| clientId | string | 是 | 客户端 ID,用于权限控制 | "e5cd7e4891" |
| grantType | string | 是 | 授权类型,目前支持 password | "password" |
| code | string | 否 | 验证码(当系统开启验证码时必填) | "1234" |
| uuid | string | 否 | 验证码唯一标识(当需要验证码时必填) | "uuid-string" |
请求示例:
{
"tenantId": "000000",
"username": "admin",
"password": "admin123",
"clientId": "e5cd7e4891bf95d1d19206ce24a7b32e",
"grantType": "password"
}
响应示例:
{
"code": 200,
"msg": "操作成功",
"data": {
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpblR5cGUiOiJsb2dpbiIsImxvZ2luSWQiOiJzeXNfdXNlcjoxIiwicm5TdHIiOiJ5MlhvbHRnd1Y2YjUzRnRMVzF4SFR1anRSUERjeGdmYyIsImNsaWVudGlkIjoiZTVjZDdlNDg5MWJmOTVkMWQxOTIwNmNlMjRhN2IzMmUiLCJ0ZW5hbnRJZCI6IjAwMDAwMCIsInVzZXJJZCI6MSwidXNlck5hbWUiOiJhZG1pbiIsImRlcHRJZCI6MTAzLCJkZXB0TmFtZSI6IuaZuuiDveaOp-WItuWtpumZoiIsImRlcHRDYXRlZ29yeSI6IiIsIm5pY2tOYW1lIjoi55av54uC55qE54uu5a2QTGkifQ.WI6iY3AgwPz7ceI8WDsVy-GaTXZnU-JKUYUTjhQdoKM",
"refresh_token": null,
"expire_in": 604800,
"refresh_expire_in": null,
"client_id": "e5cd7e4891bf95d1d19206ce24a7b32e",
"scope": null,
"openid": null
}
}
实际 Token 解析信息:
| 字段名 | 值 | 说明 |
|---|---|---|
| userId | 1 | 用户 ID |
| userName | admin | 用户名 |
| nickName | 疯狂狮子 Li | 用户昵称 |
| deptId | 103 | 部门 ID |
| deptName | 智胜技术开发团队 | 部门名称 |
| tenantId | 000000 | 租户 ID |
| clientId | e5cd7e4891... |
客户端 ID |
| loginType | login | 登录类型 |
Token 有效期: 7 天 (604800 秒)
响应参数说明:
| 参数名 | 类型 | 说明 |
|---|---|---|
| access_token | string | 访问令牌,用于 API 调用认证 |
| refresh_token | string | 刷新令牌,用于获取新的访问令牌 |
| expire_in | long | 访问令牌过期时间(秒) |
| refresh_expire_in | long | 刷新令牌过期时间(秒) |
| client_id | string | 客户端 ID |
| scope | string | 权限范围 |
| openid | string | 第三方登录标识(可为空) |
多种登录方式支持:
系统采用策略模式,支持多种登录方式:
密码登录 (grantType: "password")
邮箱登录 (grantType: "email")
短信登录 (grantType: "sms")
小程序登录 (grantType: "xcx")
错误码说明:
| 错误码 | 错误信息 | 说明 | 解决方案 |
|---|---|---|---|
| 400 | 参数校验失败 | 请求参数格式错误 | 检查参数格式和必填字段 |
| 400 | 客户端 id 异常 | clientId 不存在或被禁用 | 检查 clientId 配置 |
| 400 | 授权类型不正确 | grantType 不支持 | 使用支持的授权类型 |
| 400 | 当前系统没有开启注册功能 | 租户未开启注册 | 联系管理员开启注册功能 |
| 401 | 用户不存在 | 用户名不存在 | 检查用户名是否正确 |
| 401 | 用户已被停用 | 用户账号被禁用 | 联系管理员激活账号 |
| 401 | 密码错误 | 用户密码不正确 | 检查密码是否正确 |
| 401 | 验证码已过期 | 验证码超时 | 重新获取验证码 |
| 401 | 验证码错误 | 验证码输入错误 | 检查验证码是否正确 |
| 403 | 登录失败次数过多,账户已锁定 | 密码错误次数超限 | 等待解锁或联系管理员 |
| 500 | 租户不存在 | tenantId 无效 | 检查租户配置 |
安全特性:
密码安全:
传输安全:
会话安全:
多租户安全:
实际使用示例:
// 完整的登录实现示例(AES+RSA加密)
const axios = require('axios');
const CryptoJS = require('crypto-js');
const NodeRSA = require('node-rsa');
async function loginWithEncryption(username = 'admin', password = 'admin123') {
// 配置信息
const CONFIG = {
url: 'http://localhost/dev-api/auth/login',
clientId: 'e5cd7e4891bf95d1d19206ce24a7b32e',
tenantId: '000000',
referer: 'http://localhost/login?redirect=%252Findex',
rsaKey: 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==',
};
// 生成32位随机AES密钥
function generateAESKey() {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let result = '';
for (let i = 0; i < 32; i++) {
result += chars.charAt(Math.floor(Math.random() * chars.length));
}
return result;
}
// AES加密
function aesEncrypt(data, key) {
const keyUtf8 = CryptoJS.enc.Utf8.parse(key);
return CryptoJS.AES.encrypt(data, keyUtf8, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7,
}).toString();
}
// RSA加密AES密钥
function rsaEncrypt(aesKey) {
const pemKey = `-----BEGIN PUBLIC KEY-----\n${CONFIG.rsaKey}\n-----END PUBLIC KEY-----`;
const rsaKey = new NodeRSA(pemKey);
rsaKey.setOptions({ encryptionScheme: 'pkcs1' });
const aesKeyBase64 = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(aesKey));
return rsaKey.encrypt(aesKeyBase64, 'base64');
}
// 生成AES密钥并加密登录数据
const aesKey = generateAESKey();
const loginData = {
tenantId: CONFIG.tenantId,
username: username,
password: password,
clientId: CONFIG.clientId,
grantType: 'password',
};
const encryptedData = aesEncrypt(JSON.stringify(loginData), aesKey);
const encryptedKey = rsaEncrypt(aesKey);
// 设置请求头
const headers = {
'Content-Type': 'application/json;charset=utf-8',
clientid: CONFIG.clientId,
'encrypt-key': encryptedKey,
referer: CONFIG.referer,
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
isToken: 'false',
isEncrypt: 'true',
repeatSubmit: 'false',
};
// 发送登录请求
const response = await axios.post(CONFIG.url, encryptedData, {
headers: headers,
timeout: 10000,
});
if (response.data.code === 200 && response.data.data?.access_token) {
return response.data.data.access_token;
} else {
throw new Error(response.data.msg || 'Login failed');
}
}
// 使用示例
loginWithEncryption()
.then((token) => {
console.log('Login successful, token:', token);
})
.catch((error) => {
console.error('Login failed:', error.message);
});
快速测试脚本:
项目中提供了完整的测试脚本,位于test/目录:
test/custom-login-script.js - 完整功能版test/quick-token-getter.js - 快速获取版test/登录脚本使用说明.md - 详细使用文档接口地址: POST /auth/logout
接口描述: 用户退出登录,清除服务端会话信息
权限要求: 需要登录
请求参数: 无需请求体
请求头:
{
"Authorization": "Bearer {access_token}"
}
响应示例:
{
"code": 200,
"msg": "退出成功",
"data": null
}
功能说明:
接口地址: GET /auth/code
接口描述: 获取图形验证码,用于登录时的安全验证
权限要求: 无需认证
请求参数: 无
响应示例:
{
"code": 200,
"msg": "操作成功",
"data": {
"uuid": "d7c2c4c4-4e9d-4a5f-9c1a-2b3c4d5e6f7g",
"img": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABH..."
}
}
响应参数说明:
| 参数名 | 类型 | 说明 |
|---|---|---|
| uuid | string | 验证码唯一标识 |
| img | string | Base64 编码的验证码图片 |
使用流程:
接口地址: GET /system/user/getInfo
接口描述: 获取当前登录用户的详细信息,包括角色权限等
权限要求: 需要登录
请求参数: 无
响应示例:
{
"code": 200,
"msg": "操作成功",
"data": {
"user": {
"userId": 1,
"userName": "admin",
"nickName": "疯狂狮子Li",
"email": "admin@example.com",
"phonenumber": "13800138000",
"sex": "1",
"avatar": "/profile/avatar/default.jpg",
"status": "0",
"loginIp": "127.0.0.1",
"loginDate": "2025-01-26 10:30:00",
"tenantId": "000000",
"deptId": 103,
"deptName": "智胜技术开发团队"
},
"roles": ["admin", "common"],
"permissions": ["*:*:*"]
}
}
超级管理员权限说明:
admin 用户具有系统最高权限*:*:*,可以访问所有功能模块和执行所有操作。
接口地址: GET /auth/tenant/list
接口描述: 获取系统可用的租户列表,用于登录时选择租户
权限要求: 无需认证
请求参数: 无
响应示例:
{
"code": 200,
"msg": "操作成功",
"data": {
"tenantEnabled": true,
"voList": [
{
"tenantId": "000000",
"companyName": "杭州第一技师学院",
"domain": "hzdyjs.edu.cn",
"status": "0"
}
]
}
}
响应参数说明:
| 参数名 | 类型 | 说明 |
|---|---|---|
| tenantEnabled | boolean | 是否启用多租户功能 |
| voList | array | 租户列表 |
voList 中每项参数:
| 参数名 | 类型 | 说明 |
|---|---|---|
| tenantId | string | 租户 ID |
| companyName | string | 租户名称 |
| domain | string | 租户域名 |
| status | string | 状态(0 正常 1 停用) |
移动端使用uni-app框架,登录实现与web端保持API兼容,但在实现细节上有所差异:
网络请求配置:
// mobile/src/utils/request.js
const baseURL = 'http://localhost:8080'
const request = (options) => {
return new Promise((resolve, reject) => {
const token = getToken()
uni.request({
url: baseURL + options.url,
method: options.method || 'GET',
data: options.data || {},
header: {
'Content-Type': 'application/json',
'Authorization': token,
'clientid': 'e5cd7e4891bf95d1d19206ce24a7b32e',
'referer': baseURL,
...options.header,
},
// 响应处理逻辑...
})
})
}
登录API调用:
// 移动端登录API
export const api = {
login: (data) =>
request({
url: '/auth/login',
method: 'POST',
data: {
tenantId: data.tenantId || '000000',
username: data.username,
password: data.password,
clientId: data.clientId || 'e5cd7e4891bf95d1d19206ce24a7b32e',
grantType: data.grantType || 'password'
},
header: {
isToken: false,
isEncrypt: true,
repeatSubmit: false
}
}),
getUserInfo: () =>
request({
url: '/system/user/getInfo',
method: 'GET'
}),
// 其他API...
}
用户信息存储工具:
// mobile/src/utils/request.js
export const userStorage = {
// 保存登录信息
saveLoginInfo: (loginResult, userInfo) => {
try {
uni.setStorageSync('access_token', loginResult.access_token)
if (userInfo) {
uni.setStorageSync('userInfo', JSON.stringify(userInfo))
}
uni.setStorageSync('isLoggedIn', true)
} catch (e) {
console.error('保存登录信息失败:', e)
}
},
// 获取用户信息
getUserInfo: () => {
try {
const userInfo = uni.getStorageSync('userInfo')
return userInfo ? JSON.parse(userInfo) : null
} catch (e) {
return null
}
},
// 检查登录状态
isLoggedIn: () => {
try {
const isLoggedIn = uni.getStorageSync('isLoggedIn')
const token = uni.getStorageSync('access_token')
return !!(isLoggedIn && token)
} catch (e) {
return false
}
},
// 清除登录信息
clearLoginInfo: () => {
try {
uni.removeStorageSync('access_token')
uni.removeStorageSync('userInfo')
uni.removeStorageSync('isLoggedIn')
} catch (e) {
console.error('清除登录信息失败:', e)
}
}
}
/auth/loginAPI → 获取access_token/system/user/getInfoAPI → 获取用户详情userStorage.saveLoginInfo()缓存登录信息pages.json配置:
{
"pages": [
{
"path": "pages/login/index",
"style": {
"navigationBarTitleText": "登录",
"navigationStyle": "custom",
"navigationBarBackgroundColor": "transparent",
"backgroundColor": "transparent"
}
}
]
}
全局登录验证:
// 在每个需要登录的页面中
onLoad() {
this.checkLoginStatus();
},
methods: {
checkLoginStatus() {
if (!userStorage.isLoggedIn()) {
uni.reLaunch({
url: '/pages/login/index'
});
return false;
}
return true;
}
}
| 特性 | Web端 | 移动端 |
|---|---|---|
| 框架 | Vue 3 + TypeScript | Vue 3 + uni-app |
| 存储 | localStorage | uni.storage |
| 网络请求 | axios | uni.request |
| 路由跳转 | router.push | uni.navigateTo/reLaunch |
| UI组件 | Element Plus | uview-plus |
| 加密方式 | AES+RSA | 支持,但简化实现 |
如有认证相关问题,请联系开发团队或查看项目仓库的 Issues。
📝 维护: 用户认证登录 API 文档
🔄 更新: 2025-01-03
📁 文件: 用户认证登录 API.md