快速开始指南¶
🎯 5分钟快速体验¶
前置条件¶
确保你的开发环境已安装: - JDK 17+ - Maven 3.6+ - MySQL 8.0+ - Redis 7.0+
快速启动步骤¶
1. 准备数据库¶
# 登录MySQL
mysql -u root -p
# 创建数据库
CREATE DATABASE auth_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
# 退出
exit
2. 导入初始化数据¶
3. 启动Redis¶
4. 修改配置¶
编辑 src/main/resources/application.yml:
spring:
datasource:
url: jdbc:mysql://localhost:3306/auth_db
username: root
password: your_password # 修改为你的密码
redis:
host: localhost
port: 6379
5. 启动服务¶
6. 验证服务¶
# 检查服务健康状态
curl http://localhost:8080/actuator/health
# 获取验证码
curl http://localhost:8080/api/v1/auth/captcha
# 登录(默认账号)
curl -X POST http://localhost:8080/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{
"username": "admin",
"password": "admin123"
}'
✅ 如果看到返回的Token,说明服务已经成功启动!
🔌 集成到你的项目¶
方式一:使用SDK(推荐)¶
1. 添加依赖¶
在你的项目 pom.xml 中添加:
<dependency>
<groupId>cn.zhangziming</groupId>
<artifactId>auth-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>
2. 配置¶
在 application.yml 中添加配置:
auth:
server:
url: http://localhost:8080 # 认证服务地址
client:
id: your-client-id # 客户端ID
secret: your-client-secret # 客户端密钥
enabled: true
3. 使用注解保护接口¶
@RestController
@RequestMapping("/api/user")
public class UserController {
// 需要登录才能访问
@RequireLogin
@GetMapping("/info")
public Result getUserInfo() {
return Result.success(UserContext.getCurrentUser());
}
// 需要特定权限
@RequirePermission("user:delete")
@DeleteMapping("/{id}")
public Result deleteUser(@PathVariable Long id) {
return Result.success();
}
// 需要特定角色
@RequireRole("ADMIN")
@PostMapping("/create")
public Result createUser(@RequestBody UserDTO user) {
return Result.success();
}
}
4. 获取当前用户信息¶
@Service
public class BusinessService {
public void doSomething() {
// 获取当前登录用户
UserInfo currentUser = UserContext.getCurrentUser();
Long userId = currentUser.getUserId();
String username = currentUser.getUsername();
List<String> roles = currentUser.getRoles();
List<String> permissions = currentUser.getPermissions();
// 业务逻辑
System.out.println("当前用户: " + username);
}
}
方式二:使用Feign调用¶
1. 添加依赖¶
<dependency>
<groupId>cn.zhangziming</groupId>
<artifactId>auth-api</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2. 启用Feign¶
@SpringBootApplication
@EnableFeignClients(basePackages = "cn.zhangziming.auth.api.feign")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
3. 使用Feign客户端¶
@Service
public class UserService {
@Autowired
private AuthFeignClient authFeignClient;
public UserInfoResponse getUserInfo(String token) {
return authFeignClient.getUserInfo(token);
}
public boolean validateToken(String token) {
return authFeignClient.validateToken(token);
}
}
方式三:直接HTTP调用¶
1. 登录获取Token¶
@Service
public class AuthService {
@Autowired
private RestTemplate restTemplate;
private static final String AUTH_URL = "http://localhost:8080/api/v1";
public LoginResponse login(String username, String password) {
LoginRequest request = new LoginRequest();
request.setUsername(username);
request.setPassword(password);
ResponseEntity<Result<LoginResponse>> response = restTemplate.postForEntity(
AUTH_URL + "/auth/login",
request,
new ParameterizedTypeReference<Result<LoginResponse>>() {}
);
return response.getBody().getData();
}
}
2. 验证Token¶
public boolean validateToken(String token) {
HttpHeaders headers = new HttpHeaders();
headers.setBearerAuth(token);
HttpEntity<?> entity = new HttpEntity<>(headers);
try {
ResponseEntity<Result<UserInfoResponse>> response = restTemplate.exchange(
AUTH_URL + "/auth/userinfo",
HttpMethod.GET,
entity,
new ParameterizedTypeReference<Result<UserInfoResponse>>() {}
);
return response.getStatusCode() == HttpStatus.OK;
} catch (Exception e) {
return false;
}
}
🌐 前端集成示例¶
Vue 3 + Axios¶
1. 安装依赖¶
2. 创建API工具类¶
// src/utils/request.js
import axios from 'axios'
const service = axios.create({
baseURL: 'http://localhost:8080/api/v1',
timeout: 5000
})
// 请求拦截器
service.interceptors.request.use(
config => {
const token = localStorage.getItem('access_token')
if (token) {
config.headers['Authorization'] = `Bearer ${token}`
}
return config
},
error => {
return Promise.reject(error)
}
)
// 响应拦截器
service.interceptors.response.use(
response => {
const res = response.data
if (res.code !== 200) {
// Token过期,刷新Token
if (res.code === 1003) {
return refreshToken().then(() => {
return service(response.config)
})
}
return Promise.reject(new Error(res.message || 'Error'))
}
return res.data
},
error => {
return Promise.reject(error)
}
)
export default service
3. 创建认证API¶
// src/api/auth.js
import request from '@/utils/request'
export function login(username, password) {
return request({
url: '/auth/login',
method: 'post',
data: {
username,
password
}
})
}
export function logout() {
return request({
url: '/auth/logout',
method: 'post'
})
}
export function getUserInfo() {
return request({
url: '/auth/userinfo',
method: 'get'
})
}
export function refreshToken() {
const refreshToken = localStorage.getItem('refresh_token')
return request({
url: '/auth/refresh',
method: 'post',
data: { refreshToken }
}).then(res => {
localStorage.setItem('access_token', res.accessToken)
localStorage.setItem('refresh_token', res.refreshToken)
return res
})
}
4. 登录组件¶
<!-- src/views/Login.vue -->
<template>
<div class="login-container">
<el-form :model="loginForm" :rules="rules" ref="loginFormRef">
<el-form-item prop="username">
<el-input v-model="loginForm.username" placeholder="用户名" />
</el-form-item>
<el-form-item prop="password">
<el-input v-model="loginForm.password" type="password" placeholder="密码" />
</el-form-item>
<el-button type="primary" @click="handleLogin">登录</el-button>
</el-form>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { useRouter } from 'vue-router'
import { login, getUserInfo } from '@/api/auth'
import { ElMessage } from 'element-plus'
const router = useRouter()
const loginFormRef = ref()
const loginForm = ref({
username: '',
password: ''
})
const rules = {
username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
password: [{ required: true, message: '请输入密码', trigger: 'blur' }]
}
const handleLogin = async () => {
await loginFormRef.value.validate()
try {
const res = await login(loginForm.value.username, loginForm.value.password)
// 保存Token
localStorage.setItem('access_token', res.accessToken)
localStorage.setItem('refresh_token', res.refreshToken)
// 获取用户信息
const userInfo = await getUserInfo()
localStorage.setItem('userInfo', JSON.stringify(userInfo))
ElMessage.success('登录成功')
router.push('/')
} catch (error) {
ElMessage.error(error.message || '登录失败')
}
}
</script>
5. 路由守卫¶
// src/router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import { getUserInfo } from '@/api/auth'
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: '/login',
component: () => import('@/views/Login.vue')
},
{
path: '/',
component: () => import('@/views/Home.vue'),
meta: { requireAuth: true }
}
]
})
router.beforeEach(async (to, from, next) => {
const token = localStorage.getItem('access_token')
if (to.meta.requireAuth) {
if (!token) {
next('/login')
return
}
// 验证Token
try {
await getUserInfo()
next()
} catch (error) {
localStorage.clear()
next('/login')
}
} else {
next()
}
})
export default router
React + Axios¶
1. 创建认证上下文¶
// src/context/AuthContext.jsx
import { createContext, useState, useContext, useEffect } from 'react'
import { login as loginApi, getUserInfo } from '@/api/auth'
const AuthContext = createContext()
export function AuthProvider({ children }) {
const [user, setUser] = useState(null)
const [loading, setLoading] = useState(true)
useEffect(() => {
// 初始化时检查登录状态
checkAuth()
}, [])
const checkAuth = async () => {
const token = localStorage.getItem('access_token')
if (token) {
try {
const userInfo = await getUserInfo()
setUser(userInfo)
} catch (error) {
localStorage.clear()
}
}
setLoading(false)
}
const login = async (username, password) => {
const res = await loginApi(username, password)
localStorage.setItem('access_token', res.accessToken)
localStorage.setItem('refresh_token', res.refreshToken)
setUser(res.userInfo)
return res
}
const logout = () => {
localStorage.clear()
setUser(null)
}
const hasPermission = (permission) => {
return user?.permissions?.includes(permission) || false
}
const hasRole = (role) => {
return user?.roles?.includes(role) || false
}
return (
<AuthContext.Provider value={{ user, loading, login, logout, hasPermission, hasRole }}>
{children}
</AuthContext.Provider>
)
}
export const useAuth = () => useContext(AuthContext)
2. 使用认证¶
// src/pages/Dashboard.jsx
import { useAuth } from '@/context/AuthContext'
export default function Dashboard() {
const { user, hasPermission } = useAuth()
return (
<div>
<h1>欢迎, {user?.nickname}</h1>
{hasPermission('user:delete') && (
<button>删除用户</button>
)}
</div>
)
}
📱 移动端集成示例¶
Android (Kotlin)¶
// AuthService.kt
class AuthService(private val baseUrl: String) {
private val client = OkHttpClient()
private val gson = Gson()
fun login(username: String, password: String): LoginResponse {
val request = LoginRequest(username, password)
val json = gson.toJson(request)
val body = RequestBody.create(
"application/json".toMediaType(),
json
)
val httpRequest = Request.Builder()
.url("$baseUrl/api/v1/auth/login")
.post(body)
.build()
client.newCall(httpRequest).execute().use { response ->
val responseBody = response.body?.string()
val result = gson.fromJson(responseBody, Result::class.java)
return result.data as LoginResponse
}
}
}
iOS (Swift)¶
// AuthService.swift
class AuthService {
let baseURL = "http://localhost:8080/api/v1"
func login(username: String, password: String, completion: @escaping (Result<LoginResponse, Error>) -> Void) {
let url = URL(string: "\(baseURL)/auth/login")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let body: [String: Any] = [
"username": username,
"password": password
]
request.httpBody = try? JSONSerialization.data(withJSONObject: body)
URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error {
completion(.failure(error))
return
}
guard let data = data else { return }
do {
let result = try JSONDecoder().decode(ApiResult<LoginResponse>.self, from: data)
completion(.success(result.data))
} catch {
completion(.failure(error))
}
}.resume()
}
}
🎓 下一步¶
❓ 常见问题¶
Q1: Token过期如何处理?¶
A: SDK会自动使用RefreshToken刷新AccessToken,你也可以手动调用refresh接口。
Q2: 如何实现单点登录?¶
A: 配置OAuth2授权码模式,所有应用共享认证中心的Token。
Q3: 如何自定义权限验证逻辑?¶
A: 实现PermissionEvaluator接口并注册为Bean。
Q4: 支持哪些第三方登录?¶
A: 目前支持微信、企业微信、钉钉、GitHub等,可通过配置扩展。
需要帮助? 查看完整文档或提交Issue