USER_INFO_ENHANCEMENT.md 6.1 KB

用户信息增强功能说明

概述

本次更新增强了系统的用户信息获取能力,现在可以从登录上下文中直接获取更多用户信息,无需额外查询数据库。

修改内容

1. LoginUser 类新增常量键

文件: yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/LoginUser.java

新增以下常量:

public static final String INFO_KEY_USERNAME = "username";  // 登录用户名
public static final String INFO_KEY_MOBILE = "mobile";      // 手机号
public static final String INFO_KEY_EMAIL = "email";        // 邮箱
public static final String INFO_KEY_SEX = "sex";            // 性别
public static final String INFO_KEY_AVATAR = "avatar";      // 头像

2. OAuth2TokenServiceImpl 增强用户信息构建

文件: yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2TokenServiceImpl.java

buildUserInfo() 方法中,现在会从 AdminUserDO 读取并存储以下信息:

  • username(用户名)
  • mobile(手机号)
  • email(邮箱)
  • sex(性别)
  • avatar(头像)
  • nickname(昵称,原有)
  • deptId(部门ID,原有)

3. SecurityFrameworkUtils 新增静态方法

文件: yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/util/SecurityFrameworkUtils.java

新增以下静态方法:

// 获取登录用户名(账号)
public static String getLoginUsername()

// 获取手机号
public static String getLoginUserMobile()

// 获取邮箱
public static String getLoginUserEmail()

// 获取性别
public static Integer getLoginUserSex()

// 获取头像
public static String getLoginUserAvatar()

原有方法:

// 获取用户ID
public static Long getLoginUserId()

// 获取昵称
public static String getLoginUserNickname()

// 获取部门ID
public static Long getLoginUserDeptId()

使用示例

在 Service 中使用

import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;

@Service
public class YourService {
    
    public void someMethod() {
        // 获取当前登录用户的各种信息
        Long userId = SecurityFrameworkUtils.getLoginUserId();
        String username = SecurityFrameworkUtils.getLoginUsername();
        String nickname = SecurityFrameworkUtils.getLoginUserNickname();
        String mobile = SecurityFrameworkUtils.getLoginUserMobile();
        String email = SecurityFrameworkUtils.getLoginUserEmail();
        Integer sex = SecurityFrameworkUtils.getLoginUserSex();
        String avatar = SecurityFrameworkUtils.getLoginUserAvatar();
        Long deptId = SecurityFrameworkUtils.getLoginUserDeptId();
        
        // 使用这些信息...
    }
}

在 Controller 中使用

import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;

@RestController
@RequestMapping("/api/example")
public class ExampleController {
    
    @GetMapping("/current-user")
    public Map<String, Object> getCurrentUser() {
        Map<String, Object> userInfo = new HashMap<>();
        userInfo.put("userId", SecurityFrameworkUtils.getLoginUserId());
        userInfo.put("username", SecurityFrameworkUtils.getLoginUsername());
        userInfo.put("nickname", SecurityFrameworkUtils.getLoginUserNickname());
        userInfo.put("mobile", SecurityFrameworkUtils.getLoginUserMobile());
        userInfo.put("email", SecurityFrameworkUtils.getLoginUserEmail());
        return userInfo;
    }
}

优势

1. 性能提升

  • 无需额外数据库查询:用户信息在登录时已加载到 Token 中
  • 减少 API 调用:不需要调用 AdminUserApi.getUser() 获取用户信息
  • 降低数据库压力:减少对 system_users 表的查询

2. 代码简化

之前的写法

Long userId = SecurityFrameworkUtils.getLoginUserId();
AdminUserRespDTO user = adminUserApi.getUser(userId);
String username = user.getUsername();  // 可能为 null
String mobile = user.getMobile();

现在的写法

String username = SecurityFrameworkUtils.getLoginUsername();
String mobile = SecurityFrameworkUtils.getLoginUserMobile();

3. 一致性保证

  • 所有信息来自同一个 Token,保证数据一致性
  • 避免并发修改导致的数据不一致问题

应用场景

  1. 日志记录:记录操作用户的详细信息
  2. 权限控制:基于用户属性进行权限判断
  3. 业务逻辑:根据用户信息执行不同的业务逻辑
  4. 外部接口调用:传递用户信息给外部系统(如工单下达接口)
  5. 审计追踪:记录用户的完整信息用于审计

注意事项

  1. 返回值可能为 null:所有 getXXX() 方法都可能返回 null,使用前请做判空处理
  2. 用户信息更新:用户信息在登录时加载,如果用户信息被修改,需要重新登录才能获取最新信息
  3. 性别字段getLoginUserSex() 返回 Integer 类型,对应 SexEnum 枚举值
  4. 线程安全:这些方法从 SecurityContextHolder 获取信息,是线程安全的

实际应用:工单下达接口

WorkOrderServiceImpl 中的应用示例:

private String getCurrentUserName() {
    // 优先使用登录用户名(username),如果没有则使用昵称(nickname)
    String username = SecurityFrameworkUtils.getLoginUsername();
    if (StrUtil.isNotBlank(username)) {
        return username;
    }
    
    String nickname = SecurityFrameworkUtils.getLoginUserNickname();
    if (StrUtil.isNotBlank(nickname)) {
        return nickname;
    }
    
    return "system";
}

这样可以优先使用英文的 username,避免中文昵称导致的外部接口调用问题。

兼容性

  • ✅ 完全向后兼容
  • ✅ 不影响现有代码
  • ✅ 可选择性使用新功能
  • ✅ 无需修改数据库结构
  • ✅ 无需修改配置文件

总结

本次增强为系统提供了更便捷、高效的用户信息获取方式,特别适合需要频繁获取用户信息的场景。建议在新代码中优先使用 SecurityFrameworkUtils 的静态方法,而不是通过 API 查询数据库。