跳转至

快速开始指南

🎯 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. 导入初始化数据

# 导入表结构和初始数据
mysql -u root -p auth_db < scripts/init.sql

3. 启动Redis

# Linux/Mac
redis-server

# Windows
redis-server.exe

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. 启动服务

# 方式一:Maven
mvn spring-boot:run

# 方式二:打包后运行
mvn clean package
java -jar target/auth-core.jar

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. 安装依赖

npm install axios

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