【优化】支持登陆用户,直接读取昵称、部门等信息,也支持自定义字段
This commit is contained in:
@@ -1,48 +0,0 @@
|
||||
package cn.iocoder.yudao.framework.rpc.core.util;
|
||||
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||
import feign.RequestTemplate;
|
||||
import feign.template.HeaderTemplate;
|
||||
import feign.template.Literal;
|
||||
import feign.template.Template;
|
||||
import feign.template.TemplateChunk;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* {@link feign.Feign} 工具类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public class FeignUtils {
|
||||
|
||||
/**
|
||||
* 添加 JSON 格式的 Header
|
||||
*
|
||||
* @param requestTemplate 请求
|
||||
* @param name header 名
|
||||
* @param value header 值
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static void createJsonHeader(RequestTemplate requestTemplate, String name, Object value) {
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
// 添加 header
|
||||
String valueStr = JsonUtils.toJsonString(value);
|
||||
requestTemplate.header(name, valueStr);
|
||||
// fix:由于 OpenFeign 针对 { 会进行分词,所以需要反射修改
|
||||
// 具体分析,可见 https://zhuanlan.zhihu.com/p/360501330 文档
|
||||
Map<String, HeaderTemplate> headers = (Map<String, HeaderTemplate>)
|
||||
ReflectUtil.getFieldValue(requestTemplate, "headers");
|
||||
HeaderTemplate template = headers.get(name);
|
||||
List<Template> templateValues = (List<Template>)
|
||||
ReflectUtil.getFieldValue(template, "values");
|
||||
List<TemplateChunk> templateChunks = (List<TemplateChunk>)
|
||||
ReflectUtil.getFieldValue(templateValues.get(0), "templateChunks");
|
||||
templateChunks.set(0, Literal.create(valueStr));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,6 +17,9 @@ import java.util.Map;
|
||||
@Data
|
||||
public class LoginUser {
|
||||
|
||||
public static final String INFO_KEY_NICKNAME = "nickname";
|
||||
public static final String INFO_KEY_DEPT_ID = "deptId";
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*/
|
||||
@@ -27,6 +30,10 @@ public class LoginUser {
|
||||
* 关联 {@link UserTypeEnum}
|
||||
*/
|
||||
private Integer userType;
|
||||
/**
|
||||
* 额外的用户信息
|
||||
*/
|
||||
private Map<String, String> info;
|
||||
/**
|
||||
* 租户编号
|
||||
*/
|
||||
|
||||
@@ -13,15 +13,18 @@ import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler;
|
||||
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 的有效性
|
||||
@@ -30,6 +33,7 @@ import java.io.IOException;
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class TokenAuthenticationFilter extends OncePerRequestFilter {
|
||||
|
||||
private final SecurityProperties securityProperties;
|
||||
@@ -91,6 +95,7 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter {
|
||||
}
|
||||
// 构建登录用户
|
||||
return new LoginUser().setId(accessToken.getUserId()).setUserType(accessToken.getUserType())
|
||||
.setInfo(accessToken.getUserInfo()) // 额外的用户信息
|
||||
.setTenantId(accessToken.getTenantId()).setScopes(accessToken.getScopes());
|
||||
} catch (ServiceException serviceException) {
|
||||
// 校验 Token 不通过时,考虑到一些接口是无需登录的,所以直接返回 null 即可
|
||||
@@ -124,7 +129,16 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter {
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -91,6 +92,28 @@ public class SecurityFrameworkUtils {
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前用户
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user