Skip to content

Commit

Permalink
【优化】支持登陆用户,直接读取昵称、部门等信息,也支持自定义字段
Browse files Browse the repository at this point in the history
  • Loading branch information
YunaiV committed Apr 7, 2024
1 parent 9de92e7 commit e2c1c7d
Show file tree
Hide file tree
Showing 14 changed files with 176 additions and 89 deletions.
53 changes: 29 additions & 24 deletions sql/mysql/ruoyi-vue-pro.sql

Large diffs are not rendered by default.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
@Data
public class LoginUser {

public static final String INFO_KEY_NICKNAME = "nickname";
public static final String INFO_KEY_DEPT_ID = "deptId";

/**
* 用户编号
*/
Expand All @@ -27,6 +30,10 @@ public class LoginUser {
* 关联 {@link UserTypeEnum}
*/
private Integer userType;
/**
* 额外的用户信息
*/
private Map<String, String> info;
/**
* 租户编号
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,18 @@
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
import cn.iocoder.yudao.module.system.api.oauth2.OAuth2TokenApi;
import cn.iocoder.yudao.module.system.api.oauth2.dto.OAuth2AccessTokenCheckRespDTO;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.web.filter.OncePerRequestFilter;

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;

/**
* Token 过滤器,验证 token 的有效性
Expand All @@ -30,6 +33,7 @@
* @author 芋道源码
*/
@RequiredArgsConstructor
@Slf4j
public class TokenAuthenticationFilter extends OncePerRequestFilter {

private final SecurityProperties securityProperties;
Expand Down Expand Up @@ -91,6 +95,7 @@ private LoginUser buildLoginUserByToken(String token, Integer userType) {
}
// 构建登录用户
return new LoginUser().setId(accessToken.getUserId()).setUserType(accessToken.getUserType())
.setInfo(accessToken.getUserInfo()) // 额外的用户信息
.setTenantId(accessToken.getTenantId()).setScopes(accessToken.getScopes());
} catch (ServiceException serviceException) {
// 校验 Token 不通过时,考虑到一些接口是无需登录的,所以直接返回 null 即可
Expand Down Expand Up @@ -124,7 +129,16 @@ private LoginUser mockLoginUser(HttpServletRequest request, String token, Intege

private LoginUser buildLoginUserByHeader(HttpServletRequest request) {
String loginUserStr = request.getHeader(SecurityFrameworkUtils.LOGIN_USER_HEADER);
return StrUtil.isNotEmpty(loginUserStr) ? JsonUtils.parseObject(loginUserStr, LoginUser.class) : null;
if (StrUtil.isEmpty(loginUserStr)) {
return null;
}
try {
loginUserStr = URLDecoder.decode(loginUserStr, StandardCharsets.UTF_8); // 解码,解决中文乱码问题
return JsonUtils.parseObject(loginUserStr, LoginUser.class);
} catch (Exception ex) {
log.error("[buildLoginUserByHeader][解析 LoginUser({}) 发生异常]", loginUserStr, ex); ;
throw ex;
}
}

}
Original file line number Diff line number Diff line change
@@ -1,23 +1,36 @@
package cn.iocoder.yudao.framework.security.core.rpc;

import cn.iocoder.yudao.framework.rpc.core.util.FeignUtils;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import lombok.extern.slf4j.Slf4j;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

/**
* LoginUser 的 RequestInterceptor 实现类:Feign 请求时,将 {@link LoginUser} 设置到 header 中,继续透传给被调用的服务
*
* @author 芋道源码
*/
@Slf4j
public class LoginUserRequestInterceptor implements RequestInterceptor {

@Override
public void apply(RequestTemplate requestTemplate) {
LoginUser user = SecurityFrameworkUtils.getLoginUser();
if (user != null) {
FeignUtils.createJsonHeader(requestTemplate, SecurityFrameworkUtils.LOGIN_USER_HEADER, user);
if (user == null) {
return;
}
try {
String userStr = JsonUtils.toJsonString(user);
userStr = URLEncoder.encode(userStr, StandardCharsets.UTF_8); // 编码,避免中文乱码
requestTemplate.header(SecurityFrameworkUtils.LOGIN_USER_HEADER, userStr);
} catch (Exception ex) {
log.error("[apply][序列化 LoginUser({}) 发生异常]", user, ex);
throw ex;
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package cn.iocoder.yudao.framework.security.core.util;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
Expand Down Expand Up @@ -91,6 +92,28 @@ public static Long getLoginUserId() {
return loginUser != null ? loginUser.getId() : null;
}

/**
* 获得当前用户的昵称,从上下文中
*
* @return 昵称
*/
@Nullable
public static String getLoginUserNickname() {
LoginUser loginUser = getLoginUser();
return loginUser != null ? MapUtil.getStr(loginUser.getInfo(), LoginUser.INFO_KEY_NICKNAME) : null;
}

/**
* 获得当前用户的部门编号,从上下文中
*
* @return 部门编号
*/
@Nullable
public static Long getLoginUserDeptId() {
LoginUser loginUser = getLoginUser();
return loginUser != null ? MapUtil.getLong(loginUser.getInfo(), LoginUser.INFO_KEY_DEPT_ID) : null;
}

/**
* 设置当前用户
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import lombok.Data;

import java.util.List;
import java.util.Map;

/**
* 登录用户信息
Expand All @@ -22,6 +23,10 @@ public class LoginUser {
* 用户类型
*/
private Integer userType;
/**
* 额外的用户信息
*/
private Map<String, String> info;
/**
* 租户编号
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.core.KeyValue;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.cache.CacheUtils;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.gateway.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.gateway.util.WebFrameworkUtils;
Expand All @@ -27,7 +26,6 @@
import java.util.function.Function;

import static cn.iocoder.yudao.framework.common.util.cache.CacheUtils.buildAsyncReloadingCache;
import static cn.iocoder.yudao.framework.common.util.cache.CacheUtils.buildCache;

/**
* Token 过滤器,验证 token 的有效性
Expand Down Expand Up @@ -154,6 +152,7 @@ private LoginUser buildUser(String body) {
// 创建登录用户
OAuth2AccessTokenCheckRespDTO tokenInfo = result.getData();
return new LoginUser().setId(tokenInfo.getUserId()).setUserType(tokenInfo.getUserType())
.setInfo(tokenInfo.getUserInfo()) // 额外的用户信息
.setTenantId(tokenInfo.getTenantId()).setScopes(tokenInfo.getScopes());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,22 @@
import cn.hutool.core.map.MapUtil;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.gateway.filter.security.LoginUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

/**
* 安全服务工具类
*
* copy from yudao-spring-boot-starter-security 的 SecurityFrameworkUtils 类
*
* @author 芋道源码
*/
@Slf4j
public class SecurityFrameworkUtils {

private static final String AUTHORIZATION_HEADER = "Authorization";
Expand Down Expand Up @@ -100,7 +105,14 @@ public static Integer getLoginUserType(ServerWebExchange exchange) {
* @param user 用户
*/
public static void setLoginUserHeader(ServerHttpRequest.Builder builder, LoginUser user) {
builder.header(LOGIN_USER_HEADER, JsonUtils.toJsonString(user));
try {
String userStr = JsonUtils.toJsonString(user);
userStr = URLEncoder.encode(userStr, StandardCharsets.UTF_8); // 编码,避免中文乱码
builder.header(LOGIN_USER_HEADER, userStr);
} catch (Exception ex) {
log.error("[setLoginUserHeader][序列化 user({}) 发生异常]", user, ex);
throw ex;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import java.io.Serializable;
import java.util.List;
import java.util.Map;

@Schema(description = "RPC 服务 - OAuth2 访问令牌的校验 Response DTO")
@Data
Expand All @@ -16,6 +17,9 @@ public class OAuth2AccessTokenCheckRespDTO implements Serializable {
@Schema(description = "用户类型,参见 UserTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Integer userType;

@Schema(description = "用户信息", example = "{\"nickname\": \"芋道\"}")
private Map<String, String> userInfo;

@Schema(description = "租户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long tenantId;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

/**
* OAuth2 访问令牌 DO
Expand Down Expand Up @@ -50,6 +51,11 @@ public class OAuth2AccessTokenDO extends TenantBaseDO {
* 枚举 {@link UserTypeEnum}
*/
private Integer userType;
/**
* 用户信息
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private Map<String, String> userInfo;
/**
* 客户端编号
*
Expand Down
Loading

0 comments on commit e2c1c7d

Please sign in to comment.