Skip to content
返回

后端脚手架

脚手架

DigitalHainan Spring 微服务框架脚手架与集成指南,覆盖 POM、缓存、MyBatis、认证、OSS 等核心模块。

概述
后端脚手架

digitalhainan-security + digitalhainan-user 身份认证 ​

本文档用于指导在目标项目中完成 digitalhainan-security 和 digitalhainan-user 模块集成。 两个模块配合使用,security 负责认证鉴权,user 负责用户上下文管理。

执行顺序:

  1. 先完成「7.1.2 快速集成」的全部步骤(必须)
  2. 根据业务需求,查阅「功能集成决策索引」选择对应路径,逐项实现
  3. 遇到配置问题时参考「7.1.3 配置属性参考」
  4. 出现异常时查阅「7.1.6 常见问题」

代码约定: 所有代码示例均包含完整 import 路径和类声明,可直接用于代码生成。


7.1.1 模块简介 ​

7.1.1.1 digitalhainan-security(认证鉴权) ​

security-spring-boot-starter 提供微服务认证鉴权能力:

  • Token 认证 — 基于 Spring Security 的无状态 Token 认证(STATELESS Session)
  • 多认证源 — 支持 UAA(统一认证)、HYB(海南办)、UCS(统一通讯录)、Base64(测试)、JWT、Local 等多种认证方式
  • OAuth2 授权码 — code2Token 接口,授权码换 Token
  • Token 缓存 — Caffeine 本地缓存 / Redis 分布式缓存,可配置缓存策略
  • Token 策略 — UUID Token 策略,可扩展自定义 Token 生成策略
  • 请求过滤 — RestSecurityAuthFilter 拦截请求,解析 Token,设置 SecurityContext
  • 权限控制 — excludePath / includePath 路径白名单/黑名单
  • 登出处理 — LogoutHandler 清除 Token 缓存
  • ApiOne 客户端 — UAA/HYB/UCS 三个 ApiOne 网关客户端

Maven 坐标:

xml
<dependency>
    <groupId>cn.com.digitalhainan</groupId>
    <artifactId>security-spring-boot-starter</artifactId>
</dependency>

7.1.1.2 digitalhainan-user(用户上下文) ​

user-spring-boot-starter 提供用户信息管理能力:

  • @LoginUser 注解 — 在 Controller/方法上标注,自动加载用户信息到上下文
  • UserInfoContext — ThreadLocal 用户上下文,获取当前登录用户信息
  • UserManager — 用户信息管理接口(获取用户信息、组织、角色权限)
  • 多策略 — UAA / HYB / UCS 三种 UserManager 实现,根据请求客户端自动路由
  • 用户缓存 — Caffeine / Redis 缓存用户信息
  • AuthorizeUtils — 角色权限校验工具

Maven 坐标:

xml
<dependency>
    <groupId>cn.com.digitalhainan</groupId>
    <artifactId>user-spring-boot-starter</artifactId>
</dependency>

前置依赖:

依赖说明
digitalhainan-pom父 POM
digitalhainan-ms-common微服务公共组件
digitalhainan-cache(可选)Redis 缓存(分布式缓存场景)
apione-clientApiOne 网关客户端

当前版本: 3.1.0-SNAPSHOT


7.1.2 快速集成 ​

7.1.2.1 确认父 POM ​

xml
<parent>
    <groupId>cn.com.digitalhainan</groupId>
    <artifactId>digitalhainan-pom</artifactId>
    <version>3.1.0-SNAPSHOT</version>
</parent>

7.1.2.2 添加依赖 ​

xml
<dependencies>
    <!-- 认证鉴权 -->
    <dependency>
        <groupId>cn.com.digitalhainan</groupId>
        <artifactId>security-spring-boot-starter</artifactId>
    </dependency>
    <!-- 用户上下文 -->
    <dependency>
        <groupId>cn.com.digitalhainan</groupId>
        <artifactId>user-spring-boot-starter</artifactId>
    </dependency>
</dependencies>

7.1.2.3 配置认证参数(application.yml) ​

yaml
digitalhainan:
  security:
    # 登出 URL
    logout-url: /api/auth/logout
    # 默认请求客户端
    default-req-client: uaa
    # 免认证路径
    exclude-path:
      - /api/auth/oauth2/code2Token
      - /service/health
      - /doc.html
      - /swagger-resources/**
      - /v3/api-docs/**
    # 需认证路径
    include-path:
      - /api/**
    # 构建类型(MOCK / CUSTOM)
    build-type: CUSTOM
    # Token 缓存
    cache:
      enable: true
      cache-type: CAFFEINE   # 或 REDIS
      cache-time: 3600       # 缓存时间(秒)
      prefix: "token:"
      caffeine:
        initial-capacity: 100
        maximum-size: 100000
  # 用户模块
  user:
    cache:
      enable: true
      cache-type: CAFFEINE
      cache-time: 3600
    uaa:
      app-key: ""
# Token 策略
hnjt:
  token:
    token-type: uuid

7.1.2.4 验证清单 ​

  • [ ] Spring Boot 启动成功
  • [ ] 访问免认证路径(如 /service/health)无需 Token
  • [ ] 访问受保护路径返回 401
  • [ ] 携带有效 Token 可正常访问 API
  • [ ] @LoginUser 标注的 Controller 可获取用户信息

7.1.3 配置属性参考 ​

7.1.3.1 Security 配置 ​

配置键类型默认值说明
digitalhainan.security.logout-urlString/api/auth/logout登出 URL
digitalhainan.security.exclude-pathList[]免认证路径列表
digitalhainan.security.include-pathList["/**"]需认证路径列表
digitalhainan.security.build-typeEnum—构建类型:MOCK(测试)/ CUSTOM(生产)
digitalhainan.security.default-req-clientStringuaa默认请求客户端:uaa / hyb / ucs
digitalhainan.security.cache.enableBooleantrue是否启用 Token 缓存
digitalhainan.security.cache.cache-typeEnumCAFFEINE缓存类型:CAFFEINE / REDIS
digitalhainan.security.cache.cache-timeLong3600缓存时间(秒)
digitalhainan.security.cache.prefixStringtoken:缓存 Key 前缀
digitalhainan.security.cache.caffeine.initial-capacityInteger100Caffeine 初始容量
digitalhainan.security.cache.caffeine.maximum-sizeLong100000Caffeine 最大容量

7.1.3.2 User 配置 ​

配置键类型默认值说明
digitalhainan.user.cache.enableBooleantrue是否启用用户信息缓存
digitalhainan.user.cache.cache-typeEnumCAFFEINE缓存类型:CAFFEINE / REDIS
digitalhainan.user.cache.cache-timeLong3600缓存时间(秒)
digitalhainan.user.cache.caffeine.initial-capacityInteger100Caffeine 初始容量
digitalhainan.user.cache.caffeine.maximum-sizeLong100000Caffeine 最大容量
digitalhainan.user.uaa.app-keyString""UAA 应用 Key

7.1.3.3 Token 策略配置 ​

配置键类型默认值说明
hnjt.token.token-typeStringuuidToken 生成策略:uuid(默认)

7.1.4 核心功能使用 ​

功能集成决策索引 ​

需求场景参考章节
Token 认证流程4.1 认证流程
配置免认证路径4.2 路径白名单
获取当前用户信息4.3 用户上下文
@LoginUser 注解4.4 @LoginUser
角色权限校验4.5 权限校验
自定义认证方式4.6 自定义认证
OAuth2 授权码换 Token4.7 OAuth2
自定义 Token 策略4.8 Token 策略
自定义用户管理4.9 UserManager

7.1.4.1 认证流程 ​

  1. 客户端携带 Token 请求 API(Header: Authorization: Bearer {token})
  2. RestSecurityAuthFilter 拦截请求,解析 Token
  3. 根据 request-client Header 选择认证方式(UAA/HYB/UCS/Local)
  4. 认证成功后设置 SecurityContext 和 AccessContext
  5. 请求到达 Controller,可通过 @LoginUser 获取用户信息
请求 → RestSecurityAuthFilter → Authentication → SecurityContext → Controller

7.1.4.2 路径白名单 ​

yaml
digitalhainan:
  security:
    exclude-path:
      - /api/auth/login          # 登录接口
      - /api/auth/oauth2/code2Token
      - /service/health          # 健康检查
      - /doc.html                # Swagger
      - /swagger-resources/**
      - /v3/api-docs/**
      - /webjars/**

7.1.4.3 用户上下文 ​

java
package com.example.controller;

import cn.com.digitalhainan.user.context.UserInfoContext;
import cn.com.digitalhainan.user.model.BaseUserInfo;
import cn.com.digitalhainan.user.model.UserAccount;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 用户上下文使用示例
 * 通过 UserInfoContext 获取当前登录用户信息
 */
@RestController
public class UserContextDemoController {

    @GetMapping("/api/demo/current-user")
    public String getCurrentUser() {
        // 获取当前用户账号
        UserAccount account = UserInfoContext.getCurrentUserAccount();
        if (account == null) {
            return "未登录";
        }

        // 获取基础用户信息
        BaseUserInfo userInfo = account.getUserInfo(BaseUserInfo.class);
        String userId = userInfo.getUserId();
        String nickName = userInfo.getNickName();
        String phone = userInfo.getPhone();
        String userAccount = userInfo.getAccount();

        return "当前用户: " + nickName + " (" + userId + ")";
    }
}

7.1.4.4 @LoginUser 注解 ​

java
package com.example.controller;

import cn.com.digitalhainan.user.annotation.LoginUser;
import cn.com.digitalhainan.user.context.UserInfoContext;
import cn.com.digitalhainan.user.model.BaseUserInfo;
import cn.com.digitalhainan.user.model.UserAccount;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @LoginUser 注解使用示例
 * 标注在方法或类上,自动加载用户信息到 UserInfoContext
 */
@RestController
public class LoginUserDemoController {

    /**
     * 基础用法:加载用户基本信息
     */
    @LoginUser
    @GetMapping("/api/demo/profile")
    public String getProfile() {
        UserAccount account = UserInfoContext.getCurrentUserAccount();
        BaseUserInfo userInfo = account.getUserInfo(BaseUserInfo.class);
        return userInfo.getNickName();
    }

    /**
     * 加载用户角色权限
     */
    @LoginUser(getRoleAndPermission = true)
    @GetMapping("/api/demo/roles")
    public String getRoles() {
        UserAccount account = UserInfoContext.getCurrentUserAccount();
        return account.getRoleAndPermission().toString();
    }

    /**
     * 加载用户所有组织信息
     */
    @LoginUser(getAllOrgInfo = true)
    @GetMapping("/api/demo/orgs")
    public String getOrgs() {
        UserAccount account = UserInfoContext.getCurrentUserAccount();
        return account.getAllOrg(Object.class).toString();
    }

    /**
     * 跳过用户缓存(实时查询)
     */
    @LoginUser(skipUserCache = true)
    @GetMapping("/api/demo/realtime")
    public String getRealtimeInfo() {
        UserAccount account = UserInfoContext.getCurrentUserAccount();
        return account.getUserInfo(BaseUserInfo.class).getAccount();
    }
}

@LoginUser 注解参数:

参数类型默认值说明
getAllOrgInfobooleanfalse是否加载所有组织信息
getCurrenAppOrgInfobooleanfalse是否加载当前应用组织信息
getRoleAndPermissionbooleanfalse是否加载角色权限
skipUserCachebooleanfalse是否跳过用户缓存
skipAllOrgCachebooleanfalse是否跳过组织缓存
skipCurrentAppOrgCachebooleanfalse是否跳过当前应用组织缓存
skipRoleAndPermissionCachebooleanfalse是否跳过角色权限缓存

7.1.4.5 权限校验 ​

java
package com.example.controller;

import cn.com.digitalhainan.user.annotation.LoginUser;
import cn.com.digitalhainan.user.utils.AuthorizeUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 权限校验使用示例
 */
@RestController
public class AuthDemoController {

    @Autowired
    private AuthorizeUtils authorizeUtils;

    @LoginUser(getRoleAndPermission = true)
    @GetMapping("/api/demo/admin")
    public String adminOnly() {
        if (!authorizeUtils.hasRole("ADMIN")) {
            return "无权访问";
        }
        return "管理员操作";
    }
}

7.1.4.6 自定义认证方式 ​

实现 Authentication 接口注册为 Spring Bean:

java
package com.example.auth;

import cn.com.digitalhainan.ms.common.web.security.auth.AccessParameters;
import cn.com.digitalhainan.security.auth.AbstractAuthentication;
import cn.com.digitalhainan.security.auth.AuthInfo;
import jakarta.servlet.http.HttpServletRequest;

/**
 * 自定义认证实现示例
 */
public class CustomAuthentication extends AbstractAuthentication {

    @Override
    public AuthInfo doAuthentication(HttpServletRequest request, AccessParameters accessParameters) {
        // 自定义认证逻辑:解析 Token,查询用户信息
        AuthInfo authInfo = new AuthInfo();
        String token = parseToken(request);
        // ... 验证 token 并填充 authInfo
        authInfo.setUserId("user-id");
        authInfo.setAccount("username");
        authInfo.setNickName("昵称");
        return authInfo;
    }

    @Override
    public void doLogout(HttpServletRequest request) {
        // 登出清理逻辑
    }
}

7.1.4.7 OAuth2 授权码换 Token ​

bash
# 授权码换 Token
curl -X POST http://host:port/api/rest/oauth2/code2Token \
  -H "Content-Type: application/json" \
  -d '{"code": "授权码", "authType": "认证类型"}'

7.1.4.8 自定义 Token 策略 ​

实现 TokenStrategy 接口:

java
package com.example.token;

import cn.com.digitalhainan.security.auth.token.strategy.TokenStrategy;

/**
 * 自定义 Token 生成策略
 */
public class CustomTokenStrategy implements TokenStrategy {

    @Override
    public String generateToken() {
        // 自定义 Token 生成逻辑
        return "custom-token-" + System.currentTimeMillis();
    }
}

配置使用自定义策略:

yaml
hnjt:
  token:
    token-type: custom  # 对应 Bean 名称

7.1.4.9 自定义 UserManager ​

实现 UserManager 接口:

java
package com.example.user;

import cn.com.digitalhainan.user.manager.UserManager;
import cn.com.digitalhainan.user.model.BaseUserInfo;
import cn.com.digitalhainan.user.model.RoleAndPermission;

/**
 * 自定义用户管理实现
 */
public class CustomUserManager implements UserManager {

    @Override
    public <T extends BaseUserInfo> T getUserInfoById(String userId) {
        // 从自定义数据源获取用户信息
        return null;
    }

    @Override
    public Object getUserAllOrg(String userId) {
        return null;
    }

    @Override
    public Object getUserOrgByAppKey(String userId) {
        return null;
    }

    @Override
    public RoleAndPermission getRolesAndPermissions(String userId) {
        return null;
    }
}

7.1.5 版本变更记录 ​

v3.1.0(当前版本) ​

  • Token 策略机制重构(TokenStrategy + TokenStrategyContext)
  • OAuth2 授权码接口
  • Spring Boot 3.x / JDK 21 适配
  • Jakarta 命名空间

v3.0.0 ​

  • Spring Security 6.x 适配
  • SecurityFilterChain 配置方式
  • 多认证源策略路由

v2.0.0 ​

  • 初始版本

7.1.6 常见问题 ​

Q1:所有接口返回 401? ​

原因: excludePath 未配置登录接口和公共接口。 解决: 在 digitalhainan.security.exclude-path 中添加免认证路径。

Q2:@LoginUser 注解不生效? ​

原因: 未引入 user-spring-boot-starter 依赖,或请求未经过认证过滤器。 解决: 确保同时引入 security-spring-boot-starter 和 user-spring-boot-starter。

Q3:UserInfoContext 获取为 null? ​

原因: Controller 方法未标注 @LoginUser,或认证未通过。 解决: 在 Controller 或方法上添加 @LoginUser 注解。

Q4:Token 缓存使用 Redis 报错? ​

原因: 未引入 cache-spring-boot-starter 或 Redis 未配置。 解决: 添加缓存依赖并配置 Redis 连接,或将 cache-type 改为 CAFFEINE。

Q5:如何切换 HYB/UCS 认证源? ​

原因: 默认使用 UAA 认证。 解决: 请求 Header 中设置 request-client: hyb 或 request-client: ucs,或修改 digitalhainan.security.default-req-client。


7.1.7 版本兼容性矩阵 ​

security/userSpring BootSpring SecurityJDK说明
3.1.0-SNAPSHOT3.x6.x21当前版本
3.0.03.x6.x21Spring Boot 3.x
2.0.0 ~ 2.1.02.x5.x8/11javax 命名空间

Power By 数字海南