认证 (Auth) 模块负责系统的用户认证、授权以及会话管理,基于 JWT (JSON Web Token) 实现无状态认证。
认证模块是系统的安全核心,负责验证用户身份并授予访问权限。Tagtag Starter 认证模块采用现代化的 JWT 认证机制,实现了无状态认证,提高了系统的可扩展性和性能。
JWT (JSON Web Token) 是一种开放标准 (RFC 7519),用于在各方之间安全地传输信息作为 JSON 对象。JWT 可以被验证和信任,因为它是数字签名的。
JWT 由三部分组成,用点 (.) 分隔:
格式: header.payload.signature
┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐
│ 客户端 │ │ 服务器 │ │ 数据库 │ │ Redis │
└─────┬──────┘ └─────┬──────┘ └─────┬──────┘ └─────┬──────┘
│ │ │ │
│ 1. 登录请求 │ │ │
│────────────────▶│ │ │
│ │ │ │
│ │ 2. 验证用户名密码 │ │
│ │────────────────▶│ │
│ │ │ │
│ │ 3. 生成 JWT 令牌 │ │
│ │◀────────────────│ │
│ │ │ │
│ │ 4. 存储令牌信息 │ │
│ │────────────────▶│ │
│ │ │ │
│ 5. 返回 JWT 令牌 │ │ │
│◀────────────────│ │ │
│ │ │ │
│ │ │ │
┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐
│ 客户端 │ │ 服务器 │ │ 数据库 │ │ Redis │
└─────┬──────┘ └─────┬──────┘ └─────┬──────┘ └─────┬──────┘
│ │ │ │
│ 1. 请求携带 JWT │ │ │
│────────────────▶│ │ │
│ │ │ │
│ │ 2. 验证 JWT 有效性│ │
│ │────────────────▶│ │
│ │ │ │
│ │ 3. 检查令牌黑名单│ │
│ │────────────────▶│ │
│ │ │ │
│ │ 4. 解析用户信息 │ │
│ │◀────────────────│ │
│ │ │ │
│ │ 5. 权限校验 │ │
│ │ │ │
│ │ 6. 处理请求 │ │
│ │────────────────▶│ │
│ │ │ │
│ 7. 返回响应 │◀────────────────│ │
│◀────────────────│ │ │
│ │ │ │
┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐
│ 客户端 │ │ 服务器 │ │ 数据库 │ │ Redis │
└─────┬──────┘ └─────┬──────┘ └─────┬──────┘ └─────┬──────┘
│ │ │ │
│ 1. 刷新令牌请求 │ │ │
│────────────────▶│ │ │
│ │ │ │
│ │ 2. 验证刷新令牌 │ │
│ │────────────────▶│ │
│ │ │ │
│ │ 3. 生成新 JWT │ │
│ │◀────────────────│ │
│ │ │ │
│ │ 4. 存储新令牌信息│ │
│ │────────────────▶│ │
│ │ │ │
│ 5. 返回新 JWT │ │ │
│◀────────────────│ │ │
│ │ │ │
功能: 验证用户身份并生成 JWT 令牌。
实现细节:
登录请求:
POST /auth/login
Content-Type: application/json
{
"username": "admin",
"password": "admin123"
}
登录响应:
{
"success": true,
"data": {
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"tokenType": "Bearer",
"expiresIn": 3600
}
}
功能: 验证 JWT 令牌的有效性。
实现细节:
实现代码:
@Component
public class JwtProvider {
@Value("${jwt.secret}")
private String secret;
@Value("${jwt.expiration}")
private long expiration;
public Claims getClaimsFromToken(String token) {
return Jwts.parserBuilder()
.setSigningKey(secret.getBytes(StandardCharsets.UTF_8))
.build()
.parseClaimsJws(token)
.getBody();
}
public boolean validateToken(String token) {
try {
getClaimsFromToken(token);
return !isTokenExpired(token);
} catch (SignatureException | MalformedJwtException | ExpiredJwtException | UnsupportedJwtException | IllegalArgumentException ex) {
return false;
}
}
private boolean isTokenExpired(String token) {
Claims claims = getClaimsFromToken(token);
Date expirationDate = claims.getExpiration();
return expirationDate.before(new Date());
}
}
功能: 使用刷新令牌生成新的访问令牌。
实现细节:
刷新请求:
POST /auth/refresh
Content-Type: application/json
{
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
功能: 退出登录并使令牌失效。
实现细节:
登出请求:
POST /auth/logout
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
tagtag-module-auth
└── src
└── main
├── java
│ └── dev
│ └── tagtag
│ └── module
│ └── auth
│ ├── controller
│ │ └── AuthController.java
│ ├── entity
│ │ └── AuthUser.java
│ ├── service
│ │ ├── AuthService.java
│ │ └── impl
│ │ └── AuthServiceImpl.java
│ ├── util
│ │ ├── JwtUtil.java
│ │ └── PasswordUtil.java
│ └── vo
│ ├── LoginRequest.java
│ ├── LoginResponse.java
│ └── RefreshTokenRequest.java
└── resources
└── db
├── schema.sql
└── data
└── init.sql
frontend/apps/tagtag/src/api/core
├── auth.ts # 认证相关 API
├── captcha.ts # 验证码相关 API
└── index.ts # API 入口
功能: 提供用户登录界面,支持用户名密码登录和验证码登录。
实现细节:
代码示例:
<script setup lang="ts">
import { ref, reactive } from 'vue';
import { useRouter } from 'vue-router';
import { useAuthStore } from '@/store/auth';
import { loginApi } from '@/api/core/auth';
const router = useRouter();
const authStore = useAuthStore();
const formData = reactive({
username: '',
password: '',
captcha: '',
rememberMe: false
});
const loading = ref(false);
async function handleLogin() {
try {
loading.value = true;
const result = await loginApi(formData);
authStore.setToken(result.accessToken);
router.push('/');
} catch (error) {
console.error('登录失败:', error);
} finally {
loading.value = false;
}
}
</script>
<template>
<div class="login-container">
<div class="login-form">
<h2>Tagtag Starter 登录</h2>
<Form :model="formData" @submit.prevent="handleLogin">
<FormItem label="用户名" required>
<Input v-model:value="formData.username" placeholder="请输入用户名" />
</FormItem>
<FormItem label="密码" required>
<Input.Password v-model:value="formData.password" placeholder="请输入密码" />
</FormItem>
<FormItem label="验证码" required>
<Input v-model:value="formData.captcha" placeholder="请输入验证码" />
<img class="captcha-img" src="/api/captcha" @click="refreshCaptcha" />
</FormItem>
<FormItem>
<Checkbox v-model:checked="formData.rememberMe">记住密码</Checkbox>
</FormItem>
<FormItem>
<Button type="primary" html-type="submit" :loading="loading" block>
登录
</Button>
</FormItem>
</Form>
</div>
</div>
</template>
功能: 管理用户登录状态,包括令牌存储、用户信息存储和权限管理。
实现细节:
代码示例:
import { defineStore } from 'pinia';
import { loginApi, logoutApi, refreshTokenApi } from '@/api/core/auth';
export const useAuthStore = defineStore('auth', {
state: () => ({
token: localStorage.getItem('token') || '',
refreshToken: localStorage.getItem('refreshToken') || '',
userInfo: JSON.parse(localStorage.getItem('userInfo') || 'null'),
permissions: JSON.parse(localStorage.getItem('permissions') || '[]'),
roles: JSON.parse(localStorage.getItem('roles') || '[]')
}),
actions: {
setToken(token: string) {
this.token = token;
localStorage.setItem('token', token);
},
setRefreshToken(refreshToken: string) {
this.refreshToken = refreshToken;
localStorage.setItem('refreshToken', refreshToken);
},
setUserInfo(userInfo: any) {
this.userInfo = userInfo;
this.permissions = userInfo.permissions || [];
this.roles = userInfo.roles || [];
localStorage.setItem('userInfo', JSON.stringify(userInfo));
localStorage.setItem('permissions', JSON.stringify(this.permissions));
localStorage.setItem('roles', JSON.stringify(this.roles));
},
async login(loginData: any) {
const result = await loginApi(loginData);
this.setToken(result.accessToken);
this.setRefreshToken(result.refreshToken);
return result;
},
async logout() {
await logoutApi();
this.clearAuth();
},
async refreshToken() {
const result = await refreshTokenApi({ refreshToken: this.refreshToken });
this.setToken(result.accessToken);
this.setRefreshToken(result.refreshToken);
return result;
},
clearAuth() {
this.token = '';
this.refreshToken = '';
this.userInfo = null;
this.permissions = [];
this.roles = [];
localStorage.removeItem('token');
localStorage.removeItem('refreshToken');
localStorage.removeItem('userInfo');
localStorage.removeItem('permissions');
localStorage.removeItem('roles');
}
}
});
功能: 在请求中自动携带 JWT 令牌,处理令牌过期和刷新。
实现细节:
代码示例:
import axios from 'axios';
import { useAuthStore } from '@/store/auth';
const request = axios.create({
baseURL: import.meta.env.VITE_APP_API_BASE_URL,
timeout: 10000
});
// 请求拦截器
request.interceptors.request.use(
(config) => {
const authStore = useAuthStore();
if (authStore.token) {
config.headers.Authorization = `Bearer ${authStore.token}`;
}
return config;
},
(error) => {
return Promise.reject(error);
}
);
// 响应拦截器
request.interceptors.response.use(
(response) => {
return response.data;
},
async (error) => {
const authStore = useAuthStore();
const originalRequest = error.config;
// 处理 401 错误
if (error.response?.status === 401 && !originalRequest._retry) {
originalRequest._retry = true;
try {
// 尝试刷新令牌
await authStore.refreshToken();
// 使用新令牌重试请求
originalRequest.headers.Authorization = `Bearer ${authStore.token}`;
return request(originalRequest);
} catch (refreshError) {
// 刷新令牌失败,跳转到登录页面
authStore.clearAuth();
window.location.href = '/login';
return Promise.reject(refreshError);
}
}
return Promise.reject(error);
}
);
export default request;
| 方法 | 端点 | 描述 |
|---|---|---|
| POST | /auth/login | 用户登录 |
| POST | /auth/logout | 用户登出 |
| POST | /auth/refresh | 刷新令牌 |
| GET | /auth/me | 获取当前用户信息 |
| GET | /auth/permissions | 获取当前用户权限 |
| GET | /auth/roles | 获取当前用户角色 |
| GET | /captcha | 获取验证码 |
实现单点登录 (SSO),支持多系统间的无缝登录。
认证模块是 Tagtag Starter 系统的安全核心,基于 JWT 实现了无状态认证机制。该模块提供了完整的认证功能,包括用户登录、令牌验证、令牌刷新和用户登出等。
通过认证模块,系统实现了统一的身份验证和授权机制,确保只有授权用户才能访问系统资源。同时,认证模块支持多种扩展方式,可以根据业务需求灵活扩展。
认证模块的设计和实现遵循了安全性、性能和可扩展性原则,为系统提供了可靠的安全保障。