主体结构写好了

This commit is contained in:
Gao Wei 2022-06-10 03:03:07 +08:00
parent e7226c1b28
commit 702432e8ed
8 changed files with 365 additions and 52 deletions

View File

@ -1,8 +1,16 @@
package cn.axzo.framework.auth.constants;
public class AopConstants {
private AopConstants(){}
public static final String HEADER_TENANT = "tenantId";
public class AuthConstants {
private AuthConstants(){}
public static final String ENV_DEV="dev";
public static final String HEADER_AUTH = "authorization";
public static final String HEADER_TENANT_ID = "tenantId";
public static final String HEADER_SAAS_TENANT_ID = "SAAS_TENANT_ID";
public static final String HEADER_WORKSPACE_ID = "workspaceId";
public static final String HEADER_TERMINAL = "terminal";
public static final String HEADER_SYSTEM_TYPE = "systemType";
public static final String HEADER_SYSTEM_VERSION = "systemVersion";
@ -11,16 +19,15 @@ public class AopConstants {
public static final String HEADER_DEVICE_NO = "deviceNo";
public static final String HEADER_APP_VERSION = "appVersion";
public static final String HEADER_SAAS_TENANT_ID = "SAAS_TENANT_ID";
public static final String HEADER_WORKSPACE_ID = "workspaceId";
public static final String VISIT_TO = "visitTo";
/**
* 这个Header用在各个服务在调用pudge的/user获取用户信息的时候
*/
public static final String HEADER_ORIGINAL_URI = "originalUrl";
public static final String USER_INFO = "userinfo";
public static final String ENV_DEV="dev";
public static final String HEADER_AUTH = "authorization";
public static final String VISIT_TO = "visitTo";
}

View File

@ -29,12 +29,12 @@ public class ContextInfo {
/**
* 单位id
*/
private String ouId;
private Long ouId;
/**
* 租户id
*/
private String tenantId;
private Long tenantId;
/**
* saas租户id
@ -44,14 +44,13 @@ public class ContextInfo {
private String visitTo;
public void buildCustomUserInfo(UserInfoMap userInfoMap){
/**
* {@link cn.axzo.apollo.server.common.config.auth.UserContextFilter.PARAMETER_PROJECTID}
*/
public void buildCustomInfoByUserInfo(UserInfoMap userInfoMap){
}
public void buildCustomInfo(HttpServletRequest request) {
public void buildCustomInfoByRequest(HttpServletRequest request) {
}
}

View File

@ -0,0 +1,22 @@
package cn.axzo.framework.auth.domain;
import lombok.Data;
@Data
public class LegacyGuessMissedReq {
public static final String HEADER_LEGACY_GUESS = "legacyGuess";
private String requestParamProjectId;
private Long headerTenantId;
private Long headerSaasTenantId;
private Long headerWorkspaceId;
private Long headerOuId;
}

View File

@ -0,0 +1,41 @@
package cn.axzo.framework.auth.domain;
import lombok.Data;
/**
*
* 在2022年630版本上线之后前端会补齐Request Header里的几个信息
* 包括terminaltenantOUworkspace
* 在前端发版补齐之前后端自己要尽量补齐缺失的header信息
* 把信息补齐放到Context里使用Context的地方就直接写新业务逻辑对于历史遗留问题少一些if-else
*
* 等将来前端发版上线之后期待这些代码被删掉
*
* @author gaowei
*
*/
@Data
public class LegacyGuessMissedRsp {
public static final String MAP_KEY_FOR_RSP = "legacyGuess";
public static final String ST_NO_NEED = "__NO_NEED__";
public static final String ST_GUESS_FAILED = "__GUESS_FAILED__";
public static final String ST_GUESS_OK = "__GUESS_OK__";
private String guessSaasTenant;
private Long saasTenantId;
private String guessTerminal;
private String newTerminal;
private String guessOU;
private Long ouId;
private String guessWorkspace;
private Long workspaceId;
}

View File

@ -10,7 +10,12 @@ import javax.servlet.http.HttpServletRequest;
public class SystemAndDeviceInfo {
private String systemType;
private String systemVersion;
private String deviceKind;
private String deviceNo;
private String appVersion;
}

View File

@ -1,16 +1,163 @@
package cn.axzo.framework.auth.domain;
import java.util.HashMap;
import java.util.Map;
public class TerminalInfo {
@Deprecated
public static final String STR_TERMINAL_PMS = "PMS";
@Deprecated
public static final String NUM_TERMINAL_PMS = "1";
@Deprecated
public static final String STR_TERMINAL_CEMS = "CEMS";
@Deprecated
public static final String NUM_TERMINAL_CEMS = "2";
@Deprecated
public static final String STR_TERMINAL_CMS = "cms";
@Deprecated
public static final String NUM_TERMINAL_CMS = "3";
/**
* 从业人员
*/
@Deprecated
public static final String STR_TERMINAL_CMP = "cmp";
@Deprecated
public static final String NUM_TERMINAL_CMP = "4";
/**
* 产业工人
*/
@Deprecated
public static final String STR_TERMINAL_CM = "cm";
@Deprecated
public static final String NUM_TERMINAL_CM = "5";
/**
* 平台身份
*/
@Deprecated
public static final String STR_TERMINAL_PLAT = "plat";
/**
* 企业
*/
@Deprecated
public static final String STR_TERMINAL_ENT = "ent";
/**
* 项目
*/
@Deprecated
public static final String STR_TERMINAL_PROJ = "proj";
@Deprecated
public final static String STR_TERMINAL_CM_LEADER = "cm_leader";
@Deprecated
public final static String STR_TERMINAL_CM_WORKER = "cm_worker";
@Deprecated
public static final String STR_TERMINAL_SCREEN = "screen";
@Deprecated
public static final String STR_TERMINAL_BOSS = "boss";
@Deprecated
public static final String STR_REGULATORY_AGENCY = "regulatory_agency";
@Deprecated
public static final String STR_REGULATORY_AGENCY_SCREEN = "regulatory_agency_screen";
@Deprecated
public static final String STR_TERMINAL_RECRUIT_H5 = "recruit_h5";
@Deprecated
public static final String STR_TERMINAL_H5 = "h5";
/**
* OMS运营管理后台
*/
public static final String NT_OMS = "NT_OMS";
/**
* 企业版Web-总包
* TODO: 这里可以和大家探讨一下是否要区分总包分包我觉得有必要区分 @gaowei
*/
public static final String NT_CMS_ENT_ZB = "NT_CMS_ENT_ZB";
/**
* 项目部管理台Web
*/
public static final String NT_CMS_PROJ = "NT_CMS_PROJ";
private String terminal;
CMS = NT_CMS, (1, cms)
boolean isCMS() {
if("1".equals(terminal)) {
}
private static Map<String, String> aliasMap = new HashMap<String, String>();
static {
aliasMap.put(NT_OMS, NT_OMS);
aliasMap.put(NT_CMS_ENT_ZB, NT_CMS_ENT_ZB);
aliasMap.put(STR_TERMINAL_ENT, NT_CMS_ENT_ZB);
aliasMap.put(NT_CMS_PROJ, NT_CMS_PROJ);
aliasMap.put(STR_TERMINAL_PROJ, NT_CMS_PROJ);
// TODO: 确认cms是否对应NT_CMS_PROJ
aliasMap.put(STR_TERMINAL_CMS, NT_CMS_PROJ);
aliasMap.put(NUM_TERMINAL_CMS, NT_CMS_PROJ);
//TODO: 补齐所有的NT标签定义以及历史mapping关系@gaowei
//对于历史关系mapping起来比较麻烦的我设计了两个参数的构造函数可以直接定义NT
}
private String rawTerminalString;
private String newTerminalString;
public TerminalInfo(String rawTerminalString) {
this.rawTerminalString = rawTerminalString;
this.newTerminalString = aliasMap.get(rawTerminalString);
if (this.newTerminalString == null)
throw new IllegalArgumentException("无效的Terminal" + rawTerminalString);
}
public TerminalInfo(String rawTerminalString, String newTerminalString) {
if (newTerminalString == null)
throw new IllegalArgumentException("无效的Terminal" + newTerminalString);
this.rawTerminalString = rawTerminalString;
this.newTerminalString = newTerminalString;
}
/**
* 最好不要用
*
* @return 可能会有历史遗留的不规范的terminal字符串
*/
@Deprecated
public String getRawTerminalString() {
return rawTerminalString;
}
public String NT() {
return newTerminalString;
}
public boolean isOMS() {
return NT_OMS.equals(newTerminalString);
}
public boolean isCMS_ENT_ZB() {
return NT_CMS_ENT_ZB.equals(newTerminalString);
}
public boolean isCMS_PROJ() {
return NT_CMS_PROJ.equals(newTerminalString);
}
}

View File

@ -17,14 +17,18 @@ import org.springframework.web.context.request.ServletRequestAttributes;
import cn.axzo.framework.auth.AuthException;
import cn.axzo.framework.auth.annotation.PreBuildContext;
import cn.axzo.framework.auth.constants.AopConstants;
import cn.axzo.framework.auth.constants.AuthConstants;
import cn.axzo.framework.auth.domain.ContextInfo;
import cn.axzo.framework.auth.domain.ContextInfoHolder;
import cn.axzo.framework.auth.domain.LegacyGuessMissedReq;
import cn.axzo.framework.auth.domain.LegacyGuessMissedRsp;
import cn.axzo.framework.auth.domain.SystemAndDeviceInfo;
import cn.axzo.framework.auth.domain.TerminalInfo;
import cn.axzo.framework.auth.domain.UserInfo;
import cn.axzo.framework.auth.domain.UserInfoMap;
import cn.axzo.framework.auth.enums.EnvEnum;
import cn.azxo.framework.common.logger.logback.PodNamespacePropertyDefiner;
import cn.azxo.framework.common.utils.StrUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.lang.TypeReference;
@ -72,32 +76,37 @@ public class ContextInfoBuilderAspect {
}
public void fillInContextInfoDetail(HttpServletRequest request, ProceedingJoinPoint pjp) {
ContextInfo contextInfo = new ContextInfo();
fillContextInfoWithRequest(contextInfo, request);
String userinfoJson;
// 本地运行 分两种情况 postMan/junit
// 判断本地环境
if (getSystemProperties() == null) {
// 如果本地环境 有两种如果是postman类型调用手动调用pudge
String token = request.getHeader("Authorization");
if (CharSequenceUtil.isEmpty(token)) {
if (CharSequenceUtil.isEmpty(contextInfo.getToken())) {
// 硬逻辑 如果不携带token 可理解为junit测试 这里不覆盖 Userinfo的信息
return;
}
userinfoJson = getUserInfoFromToken(token);
userinfoJson = getUserInfoFromPudge(contextInfo, request);
} else {
// apisix 获取的请求
String userJsonInfo = request.getHeader(AopConstants.USER_INFO);
String userJsonInfo = request.getHeader(AuthConstants.USER_INFO);
AuthException.error(CharSequenceUtil.isNotEmpty(userJsonInfo),
"do not have userinfo error , please check apisix config is correct");
// 转编码
userinfoJson = Base64.decodeStr(userJsonInfo);
}
ContextInfo contextInfo = new ContextInfo();
buildUserInfo(contextInfo, userinfoJson);
fillContextInfoWithRequest(contextInfo, request);
contextInfo.buildCustomInfo(request);
// 定制一些信息的处理
contextInfo.buildCustomInfoByRequest(request);
// 把ContextInfo放到ThreadLocal中
ContextInfoHolder.set(contextInfo);
// 把ContextInfo注入到函数的入参中
MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
Method method = methodSignature.getMethod();
Class<?>[] parameterTypes = method.getParameterTypes();
@ -111,15 +120,24 @@ public class ContextInfoBuilderAspect {
}
public String getUserInfoFromToken(String token) {
public String getUserInfoFromPudge(ContextInfo contextInfo, HttpServletRequest originalRequest) {
// postman调用
String customerEnv = getCustomerEnv();
customerEnv = CharSequenceUtil.isEmpty(customerEnv) ? AopConstants.ENV_DEV : customerEnv;
customerEnv = CharSequenceUtil.isEmpty(customerEnv) ? AuthConstants.ENV_DEV : customerEnv;
String url = EnvEnum.getValueByKey(customerEnv);
AuthException.error(CharSequenceUtil.isNotEmpty(url), "There is no correct path to request");
try {
String response = HttpRequest.get(url).header("Authorization", token).execute().body();
HttpRequest request = HttpRequest.get(url).header(AuthConstants.HEADER_AUTH, contextInfo.getToken())
.header(AuthConstants.HEADER_DEVICE_NO, contextInfo.getSystemAndDeviceInfo().getDeviceNo())
.header(AuthConstants.HEADER_TERMINAL, contextInfo.getTerminalInfo().getRawTerminalString())
.header(AuthConstants.HEADER_SAAS_TENANT_ID, contextInfo.getSaasTenantId().toString())
.header(AuthConstants.HEADER_ORIGINAL_URI, originalRequest.getRequestURI());
//期待未来前端补齐header之后删掉这一行以及相关代码
request = request.header(LegacyGuessMissedReq.HEADER_LEGACY_GUESS, buildLegacyGuessMissedReqString(contextInfo, originalRequest));
String response = request.execute().body();
// 使用token获取用户信息
AuthException.error(CharSequenceUtil.isNotEmpty(response), "not find user by token from pudge");
return response;
@ -128,6 +146,27 @@ public class ContextInfoBuilderAspect {
}
}
/**
* 期待着前端上线之后header都补齐这些代码可以全都删掉
*
* @param contextInfo
* @param originalRequest
* @return
*/
@Deprecated
private String buildLegacyGuessMissedReqString(ContextInfo contextInfo, HttpServletRequest originalRequest) {
LegacyGuessMissedReq req = new LegacyGuessMissedReq();
req.setHeaderOuId(contextInfo.getOuId());
req.setHeaderSaasTenantId(contextInfo.getSaasTenantId());
req.setHeaderTenantId(contextInfo.getTenantId());
req.setHeaderWorkspaceId(contextInfo.getWorkspaceId());
req.setRequestParamProjectId(originalRequest.getParameter("projectId"));
if(req.getRequestParamProjectId() == null)
req.setRequestParamProjectId("");
return JSONUtil.toJsonStr(req);
}
/**
* 从env/properties 获取my_pod_namespace 的value
*/
@ -149,20 +188,20 @@ public class ContextInfoBuilderAspect {
SystemAndDeviceInfo sdInfo = new SystemAndDeviceInfo();
// 请求头获取数据
sdInfo.setAppVersion(request.getHeader(AopConstants.HEADER_APP_VERSION));
sdInfo.setDeviceKind(request.getHeader(AopConstants.HEADER_DEVICE_KIND));
sdInfo.setDeviceNo(request.getHeader(AopConstants.HEADER_DEVICE_NO));
sdInfo.setSystemType(request.getHeader(AopConstants.HEADER_SYSTEM_TYPE));
sdInfo.setAppVersion(request.getHeader(AuthConstants.HEADER_APP_VERSION));
sdInfo.setDeviceKind(request.getHeader(AuthConstants.HEADER_DEVICE_KIND));
sdInfo.setDeviceNo(request.getHeader(AuthConstants.HEADER_DEVICE_NO));
sdInfo.setSystemType(request.getHeader(AuthConstants.HEADER_SYSTEM_TYPE));
sdInfo.setSystemVersion(request.getHeader(AuthConstants.HEADER_SYSTEM_VERSION));
contextInfo.setSystemAndDeviceInfo(sdInfo);
contextInfo.setTenantId(request.getHeader(AopConstants.HEADER_TENANT));
contextInfo.setVisitTo(request.getHeader(AopConstants.VISIT_TO));
contextInfo.setToken(request.getHeader(AopConstants.HEADER_AUTH));
String saasTenantId = request.getHeader(AopConstants.HEADER_SAAS_TENANT_ID);
contextInfo.setSaasTenantId(CharSequenceUtil.isEmpty(saasTenantId) ? null : Long.valueOf(saasTenantId));
String workspaceId = request.getHeader(AopConstants.HEADER_WORKSPACE_ID);
contextInfo.setWorkspaceId(CharSequenceUtil.isEmpty(workspaceId) ? null : Long.valueOf(workspaceId));
contextInfo.setToken(request.getHeader(AuthConstants.HEADER_AUTH));
contextInfo.setTerminalInfo(new TerminalInfo(request.getHeader(AuthConstants.HEADER_TERMINAL)));
contextInfo.setTenantId(StrUtil.nullSafeParseLong(request.getHeader(AuthConstants.HEADER_TENANT_ID)));
contextInfo.setSaasTenantId(StrUtil.nullSafeParseLong(request.getHeader(AuthConstants.HEADER_SAAS_TENANT_ID)));
contextInfo.setWorkspaceId(StrUtil.nullSafeParseLong(request.getHeader(AuthConstants.HEADER_WORKSPACE_ID)));
contextInfo.setVisitTo(request.getHeader(AuthConstants.VISIT_TO));
}
public void buildUserInfo(ContextInfo contextInfo, String userJsonInfo) {
@ -174,7 +213,34 @@ public class ContextInfoBuilderAspect {
BeanUtil.fillBeanWithMap(map, userInfo, false);
contextInfo.setUserInfo(userInfo);
contextInfo.buildCustomUserInfo(new UserInfoMap(map));
fillLegacyGuess(contextInfo, map);
contextInfo.buildCustomInfoByUserInfo(new UserInfoMap(map));
}
/**
* 期待着前端上线之后header都补齐这些代码可以全都删掉
*
* @param contextInfo
* @param map 整个userInfoMap里面放着一个legacy guess的结果
*/
@Deprecated
private void fillLegacyGuess(ContextInfo contextInfo, Map<String, Object> map) {
LegacyGuessMissedRsp rsp = new LegacyGuessMissedRsp();
BeanUtil.fillBeanWithMap((Map<?,?>) map.get(LegacyGuessMissedRsp.MAP_KEY_FOR_RSP), rsp, false);
if(LegacyGuessMissedRsp.ST_GUESS_OK.equals(rsp.getGuessSaasTenant())) {
contextInfo.setSaasTenantId(rsp.getSaasTenantId());
}
if(LegacyGuessMissedRsp.ST_GUESS_OK.equals(rsp.getGuessTerminal())) {
contextInfo.setTerminalInfo(new TerminalInfo(contextInfo.getTerminalInfo().getRawTerminalString(), rsp.getGuessTerminal()));
}
if(LegacyGuessMissedRsp.ST_GUESS_OK.equals(rsp.getGuessWorkspace())) {
contextInfo.setWorkspaceId(rsp.getWorkspaceId());
}
if(LegacyGuessMissedRsp.ST_GUESS_OK.equals(rsp.getGuessOU())) {
contextInfo.setOuId(rsp.getOuId());
}
}
}

View File

@ -0,0 +1,26 @@
package cn.azxo.framework.common.utils;
/**
*
* 原来的工具类名字太长了我弄一个名字短一些的
* 把一些原来自己方便使用的小函数写几个在这里
*
* @author gaowei
*
*/
public abstract class StrUtil extends StringUtils {
public static String killNull(String input) {
if(input == null)
return "";
return input;
}
public static Long nullSafeParseLong(String input) {
if(input == null)
return 0L;
if("".equals(input))
return 0L;
return Long.valueOf(input);
}
}