feat: 增加登陆相关信息

This commit is contained in:
zengxiaobo 2024-04-28 16:03:44 +08:00
parent a95e2cc449
commit 37b646f708
6 changed files with 254 additions and 0 deletions

View File

@ -36,6 +36,11 @@
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -2,6 +2,7 @@ package cn.axzo.foundation.web.support.config;
import cn.axzo.foundation.util.FastjsonUtils;
import cn.axzo.foundation.web.support.AppRuntime;
import cn.axzo.foundation.web.support.context.AxContextInterceptor;
import cn.axzo.foundation.web.support.exception.AbstractExceptionHandler;
import cn.axzo.foundation.web.support.interceptors.PrettyPrintInterceptor;
import cn.axzo.foundation.web.support.interceptors.PrintVerboseInterceptor;
@ -187,6 +188,7 @@ public class DefaultWebMvcConfig extends DelegatingWebMvcConfiguration implement
registry.addInterceptor(e);
});
}
registry.addInterceptor(new AxContextInterceptor(appRuntime));
}
/**

View File

@ -0,0 +1,89 @@
package cn.axzo.foundation.web.support.context;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.ttl.TransmittableThreadLocal;
import com.google.common.base.Charsets;
import com.google.common.base.Strings;
import com.google.common.io.BaseEncoding;
import lombok.*;
import org.apache.commons.lang3.BooleanUtils;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Optional;
import java.util.function.BiFunction;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class AxContext {
private static final TransmittableThreadLocal<AxContext> CONTEXT = new TransmittableThreadLocal();
private static final TransmittableThreadLocal<HttpServletRequest> REQUEST = new TransmittableThreadLocal();
private AxUser axUser;
private Long ouId;
public static void set(AxContext contextInfo) {
CONTEXT.set(contextInfo);
}
public static Optional<AxContext> get() {
return Optional.ofNullable(CONTEXT.get());
}
public static void clear() {
CONTEXT.remove();
}
public static void setRequest(HttpServletRequest request) {
REQUEST.set(request);
}
public static Optional<HttpServletRequest> getRequest() {
return Optional.ofNullable(REQUEST.get());
}
public static boolean init() {
if (!getRequest().isPresent()) {
return false;
}
HttpServletRequest request = getRequest().get();
AxContext context = AxContext.builder().build();
Boolean[] initialled = Arrays.stream(HeaderEnum.values())
.map(e -> e.getFiller().apply(request, context))
.toArray(Boolean[]::new);
//所有的header设置成功才算成功
if (BooleanUtils.and(initialled)) {
set(context);
return true;
}
return false;
}
@AllArgsConstructor
@Getter
public enum HeaderEnum {
USER("用户信息", (request, context) -> {
String userHeader = request.getHeader("userinfo");
if (Strings.isNullOrEmpty(userHeader)) {
return false;
}
String userStr = new String(BaseEncoding.base64().decode(userHeader), Charsets.UTF_8);
context.setAxUser(JSONObject.parseObject(userStr, AxUser.class));
return true;
}),
OU_ID("部门ID", (request, context) -> {
String ouIdHeader = request.getHeader("ouId");
if (Strings.isNullOrEmpty(ouIdHeader)) {
return false;
}
context.setOuId(Long.parseLong(ouIdHeader));
return true;
});
private final String desc;
private final BiFunction<HttpServletRequest, AxContext, Boolean> filler;
}
}

View File

@ -0,0 +1,86 @@
package cn.axzo.foundation.web.support.context;
import cn.axzo.foundation.enums.AppEnvEnum;
import cn.axzo.foundation.web.support.AppRuntime;
import cn.axzo.foundation.web.support.rpc.HttpClient;
import cn.axzo.foundation.web.support.rpc.OkHttpClientImpl;
import cn.axzo.foundation.web.support.rpc.RequestParams;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
/**
* 1. 从容器内调用, ->apisix->this server可以从header中直接获取
* 2. 非prd环境支持Authorization: Raw {personId:xxx}
* 3. 非prd环境支持通过token到puge换
*/
@Slf4j
@RequiredArgsConstructor
public class AxContextInterceptor implements HandlerInterceptor {
private final AppRuntime appRuntime;
private final static HttpClient HTTP_CLIENT = OkHttpClientImpl.builder().build();
private final static Map<AppEnvEnum, String> ENV_HOSTS = ImmutableMap.of(
AppEnvEnum.local, "http://test-api.axzo.cn/pudge/webApi/oauth/apisix/authentication",
AppEnvEnum.dev, "http://dev-app.axzo.cn/pudge/webApi/oauth/apisix/authentication",
AppEnvEnum.test, "http://test-api.axzo.cn/pudge/webApi/oauth/apisix/authentication",
AppEnvEnum.pre, "http://pre-api.axzo.cn/pudge/webApi/oauth/apisix/authentication"
);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
AxContext.clear();
AxContext.setRequest(request);
boolean initialled = AxContext.init();
if (initialled) {
return true;
}
String authorization = request.getHeader("Authorization");
if (!Strings.isNullOrEmpty(authorization) && appRuntime.getEnv() != AppEnvEnum.prd) {
return initByAuthorization(authorization);
}
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) {
AxContext.clear();
}
/**
* 支持传入明文的authentication 或者通过puge接口支持
* 明文格式: authentication: Raw {ouid:xxx, axUser:{personId:xxx}}
* puge接口返回结果参考 test.resources.authentication.json
*/
private boolean initByAuthorization(String authorization) {
AxContext context = null;
if (authorization.startsWith("Raw")) {
context = JSONObject.parseObject(StringUtils.removeStart(authorization, "Raw "), AxContext.class);
}
if (authorization.startsWith("Bearer")) {
String result = HTTP_CLIENT.get(ENV_HOSTS.get(appRuntime.getEnv()), RequestParams.FormParams.builder()
.headers(ImmutableMap.of("Authorization", authorization))
.build());
JSONObject userinfo = JSONObject.parseObject(result).getJSONObject("userinfo");
context = AxContext.builder()
.ouId(userinfo.getLong("ouId"))
.axUser(userinfo.toJavaObject(AxUser.class))
.build();
}
if (context != null) {
AxContext.set(context);
return true;
}
return false;
}
}

View File

@ -0,0 +1,31 @@
package cn.axzo.foundation.web.support.context;
import lombok.*;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class AxUser {
private Long personId;
private VerifyStatusEnum verifyStatus;
private String realName;
private transient String phoneNumber;
@Getter
@RequiredArgsConstructor
public enum VerifyStatusEnum {
//状态 0 - 未激活, 1 - 已激活2 - 禁用,3- 认证失败
NOT_VERIFIED(0, "未认证"),
VERIFYING(1, "认证中"),
VERIFY_SUCCESS(2, "认证成功"),
VERIFY_FAILED(3, "认证失败"),
;
private final Integer code;
private final String message;
}
}

View File

@ -0,0 +1,41 @@
{
"appVersion": "0",
"ouType": 6,
"enabled": true,
"acntId": 9000456,
"idFaceUrl": "https://axzo-test.oss-cn-chengdu.aliyuncs.com/idcard/idfaceurl/21664884838922395543357.jpg",
"verifyStatus": "VERIFY_SUCCESS",
"identityType": 5,
"ouId": 5144,
"id": 9000456,
"workspaceId": 335,
"avatarUrl": "https://industrial-public.oss-cn-shanghai.aliyuncs.com/avator/default_avator.png",
"sex": "2",
"ipAddress": "10.0.3.225",
"acctId": 9000456,
"loginDevice": "NT_OMS_WEB",
"terminal": "NT_OMS_WEB",
"userId": 2003154,
"realName": "金海洋",
"faceUrl": "https://axzo-test.oss-cn-chengdu.aliyuncs.com/idcard/idfaceurl/21664884838922395543357.jpg",
"workspaceType": 6,
"phoneNumber": "18008065266",
"identityId": 2003154,
"verifiedStatus": 2,
"personId": 9000456,
"legacyGuess": {
"ouType": 6,
"workspaceType": 6,
"guessTerminal": "__GUESS_OK__",
"guessOU": "__GUESS_OK__",
"ouId": 5144,
"guessWorkspace": "__GUESS_OK__",
"guessSaasTenant": "__NO_NEED__",
"workspaceJoinType": 0,
"saasTenantId": 0,
"newTerminal": "NT_OMS_WEB",
"workspaceId": 335
},
"axzoId": 9000456
}