Przeglądaj źródła

新增上下文鉴权组件

yucheng 3 lat temu
rodzic
commit
89b4d4adea

+ 0 - 87
dmp-common/src/main/java/com/persagy/dmp/common/handler/AppContextHandler.java

@@ -1,87 +0,0 @@
-package com.persagy.dmp.common.handler;
-
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.json.JSONObject;
-import com.persagy.dmp.common.context.AppContext;
-import com.persagy.dmp.common.helper.SpringHelper;
-import com.persagy.dmp.common.constant.CommonConstant;
-import org.springframework.web.servlet.ModelAndView;
-import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-/**
- * 上下文 拦截器
- * @author Charlie Yu
- * @date 2021-06-25
- */
-public class AppContextHandler extends HandlerInterceptorAdapter {
-
-    @Override
-    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
-        // 运维平台token认证
-        if(StrUtil.isNotBlank(request.getHeader("token"))) {
-            accessTokenInfo(request.getHeader("token"));
-        } else if(StrUtil.isNotBlank(request.getParameter("groupCode"))) {
-            // 请求参数中包含groupCode,由于没有标识位,暂时用这种方式判断吧
-            accessRequestInfo(request);
-        } else {
-            // 其他情况,按现有系统默认不验证的逻辑,其他情况就是默认放行,不必处理。最好是抛401
-        }
-        return true;
-    }
-
-    /**
-     * 根据token获取上下文信息
-     * @param token
-     */
-    private void accessTokenInfo(String token){
-        // 是否启用token拦截
-        boolean enabled = SpringHelper.getBoolean("persagy.common.token.enabled", true);
-        if(!enabled) {
-            return;
-        }
-        // 从token中解析数据
-//        SecureAES aes = new SecureAES("63499E35378AE1B0733E3FED7F780B68", "C0E7BD39B52A15C7");
-        JSONObject tokenObj = new JSONObject();
-//        try {
-//            tokenObj = aes.decryptToken(token);
-//        } catch (UnsupportedEncodingException e) {
-//            throw new AESDecryptException("token解析异常");
-//        }
-        // 获取值
-        String groupCode = tokenObj.getStr("groupCode");
-        String appId = tokenObj.getStr("appId");
-        String accountId = tokenObj.getStr("accountId");
-        AppContext.getContext().setGroupCode(groupCode);
-        AppContext.getContext().setAppId(appId);
-        AppContext.getContext().setAccountId(accountId);
-    }
-
-    /**
-     * 从请求参数中获取上下文
-     * @param request
-     */
-    private void accessRequestInfo(HttpServletRequest request) {
-        AppContext.getContext().setGroupCode(request.getParameter("groupCode"));
-        AppContext.getContext().setProjectId(request.getParameter("projectId"));
-        AppContext.getContext().setAppId(request.getParameter("appId"));
-        String userId = request.getParameter("userId");
-        // 无用户时,默认为默认系统用户
-        if(StrUtil.isBlank(userId)) {
-            userId = CommonConstant.DEFAULT_ID;
-        }
-        AppContext.getContext().setAccountId(userId);
-    }
-
-    @Override
-    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
-        AppContext.unload();
-    }
-
-    @Override
-    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
-        AppContext.unload();
-    }
-}

+ 11 - 0
dmp-common/src/main/java/com/persagy/dmp/common/handler/CommonExceptionHandler.java

@@ -15,6 +15,7 @@ import org.springframework.web.bind.annotation.ResponseStatus;
 import org.springframework.web.bind.annotation.RestControllerAdvice;
 import org.springframework.web.servlet.NoHandlerFoundException;
 
+import javax.security.auth.message.AuthException;
 import javax.validation.ValidationException;
 import java.sql.SQLException;
 
@@ -113,6 +114,16 @@ public class CommonExceptionHandler {
     }
 
     /**
+     *  body体未找到
+     */
+    @ResponseStatus(HttpStatus.UNAUTHORIZED)
+    @ExceptionHandler(AuthException.class)
+    public CommonResult handlerAuthException(AuthException e) {
+        log.error(e.getMessage(), e);
+        return ResultHelper.failure(ResponseCode.A0220.getCode(), ResponseCode.A0220.getDesc());
+    }
+
+    /**
      * 系统默认繁忙
      */
     @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)

+ 19 - 0
dmp-comp/dmp-auth/README.md

@@ -0,0 +1,19 @@
+登录认证
+============ 
+请求日志处理切面
+上下文拦截器
+
+说明
+---------------
+配置说明
+persagy.common.auth.channel=-1
+. -1: 不鉴权【默认】 - 直接从HEAD中获取上下文信息
+. 1: 运维平台2.0   - 从head中获取上下文信息,并校验集团、项目是否有效
+. 2: BOSS         - 校验token,并从token中获取上下文信息
+```
+
+```
+
+最新变化
+---------------
+

+ 24 - 0
dmp-comp/dmp-auth/pom.xml

@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>dmp-comp</artifactId>
+        <groupId>com.persagy</groupId>
+        <version>1.0.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>dmp-auth</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.persagy</groupId>
+            <artifactId>dmp-common</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.persagy</groupId>
+            <artifactId>integrated-log-spring-boot-starter</artifactId>
+        </dependency>
+    </dependencies>
+    
+</project>

+ 1 - 1
dmp-server/src/main/java/com/persagy/aspects/RequestLogAspect.java

@@ -1,4 +1,4 @@
-package com.persagy.aspects;
+package com.persagy.dmp.auth.aspect;
 
 import cn.hutool.core.util.ArrayUtil;
 import cn.hutool.core.util.IdUtil;

+ 42 - 0
dmp-comp/dmp-auth/src/main/java/com/persagy/dmp/auth/constant/AuthChannelEnum.java

@@ -0,0 +1,42 @@
+package com.persagy.dmp.auth.constant;
+
+import lombok.Getter;
+
+/**
+ * 鉴权渠道
+ * @author Charlie Yu
+ * @date 2021-11-02
+ */
+@Getter
+public enum AuthChannelEnum {
+
+    /** 不鉴权 */
+    NONE(-1, "noneAuthServiceImpl"),
+    /** 运维平台2.0 */
+    EMS(1, "emsAuthServiceImpl"),
+    /** BOSS */
+    BOSS(2, "bossAuthServiceImpl");
+
+    private Integer index;
+    private String name;
+
+    AuthChannelEnum(Integer index, String name) {
+        this.index = index;
+        this.name = name;
+    }
+
+    /**
+     * 获取Enum
+     * @param index
+     * @return
+     */
+    public static AuthChannelEnum load(Integer index) {
+        for (AuthChannelEnum value: values()) {
+            if (value.getIndex().equals(index)) {
+                return value;
+            }
+        }
+        // 没有匹配的,返回默认
+        return AuthChannelEnum.NONE;
+    }
+}

+ 43 - 0
dmp-comp/dmp-auth/src/main/java/com/persagy/dmp/auth/handler/AppContextHandler.java

@@ -0,0 +1,43 @@
+package com.persagy.dmp.auth.handler;
+
+import com.persagy.dmp.auth.service.AuthService;
+import com.persagy.dmp.auth.service.AuthServiceFactory;
+import org.springframework.web.servlet.ModelAndView;
+import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
+
+import javax.security.auth.message.AuthException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * 上下文 拦截器
+ * @author Charlie Yu
+ * @date 2021-06-25
+ */
+public class AppContextHandler extends HandlerInterceptorAdapter {
+
+    @Override
+    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+        AuthService authService = AuthServiceFactory.getAuthService();
+        // 登录校验
+        boolean isSuccess = authService.validateLogin(request, response);
+        if(!isSuccess) {
+            // 鉴权器处理
+            authService.loginFailure(request, response);
+            throw new AuthException("登录认证失败!");
+        }
+        // 登录成功处理
+        authService.loginSuccess(request, response);
+        return true;
+    }
+
+    @Override
+    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
+        AuthServiceFactory.getAuthService().release(request, response);
+    }
+
+    @Override
+    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
+        AuthServiceFactory.getAuthService().release(request, response);
+    }
+}

+ 40 - 0
dmp-comp/dmp-auth/src/main/java/com/persagy/dmp/auth/service/AuthService.java

@@ -0,0 +1,40 @@
+package com.persagy.dmp.auth.service;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * 鉴权接口
+ * @author Charlie Yu
+ * @date 2021-11-02
+ */
+public interface AuthService {
+
+    /**
+     * 登录认证
+     * @param request
+     * @param response
+     */
+    boolean validateLogin(HttpServletRequest request, HttpServletResponse response);
+
+    /**
+     * 登录成功处理
+     * @param request
+     * @param response
+     */
+    void loginSuccess(HttpServletRequest request, HttpServletResponse response);
+
+    /**
+     * 登录失败处理
+     * @param request
+     * @param response
+     */
+    void loginFailure(HttpServletRequest request, HttpServletResponse response);
+
+    /**
+     * 请求结束
+     * @param request
+     * @param response
+     */
+    void release(HttpServletRequest request, HttpServletResponse response);
+}

+ 27 - 0
dmp-comp/dmp-auth/src/main/java/com/persagy/dmp/auth/service/AuthServiceFactory.java

@@ -0,0 +1,27 @@
+package com.persagy.dmp.auth.service;
+
+import com.persagy.dmp.auth.constant.AuthChannelEnum;
+import com.persagy.dmp.common.helper.SpringHelper;
+
+/**
+ * 鉴权工厂
+ * @author Charlie Yu
+ * @date 2021-11-02
+ */
+public class AuthServiceFactory {
+
+    private static AuthService authService;
+
+    /**
+     * 获取鉴权服务
+     * @return
+     */
+    public static AuthService getAuthService() {
+        if(authService == null) {
+            Integer authChannel = SpringHelper.getInt("persagy.common.auth.channel", -1);
+            String beanName = AuthChannelEnum.load(authChannel).getName();
+            authService = SpringHelper.getBean(beanName);
+        }
+        return authService;
+    }
+}

+ 55 - 0
dmp-comp/dmp-auth/src/main/java/com/persagy/dmp/auth/service/impl/AbstractAuthServiceImpl.java

@@ -0,0 +1,55 @@
+package com.persagy.dmp.auth.service.impl;
+
+import cn.hutool.core.util.StrUtil;
+import com.persagy.dmp.auth.service.AuthService;
+import com.persagy.dmp.common.constant.CommonConstant;
+import com.persagy.dmp.common.context.AppContext;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * 登录认证处理抽象类
+ * @author Charlie Yu
+ * @date 2021-11-02
+ */
+public abstract class AbstractAuthServiceImpl implements AuthService {
+
+    @Override
+    public boolean validateLogin(HttpServletRequest request, HttpServletResponse response) {
+        // 登录认证通常在网关完成,无网关服务在此完成
+        return true;
+    }
+
+    @Override
+    public void loginSuccess(HttpServletRequest request, HttpServletResponse response) {
+
+    }
+
+    @Override
+    public void loginFailure(HttpServletRequest request, HttpServletResponse response) {
+
+    }
+
+    @Override
+    public void release(HttpServletRequest request, HttpServletResponse response) {
+        // 释放上下文缓存
+        AppContext.unload();
+    }
+
+    /**
+     * 从请求中装载上下文
+     * @param request
+     */
+    protected void loadContextByRequest(HttpServletRequest request) {
+        AppContext context = AppContext.getContext();
+        context.setGroupCode(request.getParameter(AppContext.GROUP_CODE));
+        context.setProjectId(request.getParameter(AppContext.PROJECT_ID));
+        context.setAppId(request.getParameter(AppContext.APP_ID));
+        context.setAccountId(request.getParameter("userId"));
+        // 无用户时,默认为默认系统用户
+        if(StrUtil.isBlank(context.getAccountId())) {
+            context.setAccountId(CommonConstant.DEFAULT_ID);
+        }
+    }
+}

+ 58 - 0
dmp-comp/dmp-auth/src/main/java/com/persagy/dmp/auth/service/impl/BossAuthServiceImpl.java

@@ -0,0 +1,58 @@
+package com.persagy.dmp.auth.service.impl;
+
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.crypto.symmetric.AES;
+import com.alibaba.fastjson.JSONObject;
+import com.persagy.dmp.common.context.AppContext;
+import com.persagy.dmp.common.helper.SpringHelper;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * BOSS 鉴权实现类
+ * 校验token,并从token中获取上下文信息
+ * @author Charlie Yu
+ * @date 2021-11-02
+ */
+@Slf4j
+public class BossAuthServiceImpl extends AbstractAuthServiceImpl{
+
+    @Override
+    public boolean validateLogin(HttpServletRequest request, HttpServletResponse response) {
+        // 获取token
+        String token = request.getHeader("token");
+        if(StrUtil.isBlank(token)) {
+            log.error("未获取到token!");
+            return false;
+        }
+        return super.validateLogin(request, response);
+    }
+
+    @Override
+    public void loginSuccess(HttpServletRequest request, HttpServletResponse response) {
+        // 解析token对象
+        JSONObject info = getTokenInfo(request.getHeader("token"));
+        // 回写上下文
+        AppContext.getContext().setGroupCode(info.getString(AppContext.GROUP_CODE));
+        AppContext.getContext().setProjectId(info.getString(AppContext.PROJECT_ID));
+        AppContext.getContext().setAppId(info.getString(AppContext.APP_ID));
+        AppContext.getContext().setAccountId(info.getString(AppContext.ACCOUNT_ID));
+    }
+
+    /**
+     * 解析token对象
+     * @param token
+     * @return
+     */
+    private JSONObject getTokenInfo(String token) {
+        // 获取配置密钥
+        String accessKey = SpringHelper.getString("persagy.common.token.key", "63499E35378AE1B0733E3FED7F780B68");
+        String accessSecret = SpringHelper.getString("persagy.common.token.secret", "C0E7BD39B52A15C7");
+        // 解析token
+        AES aes = new AES("CBC","PKCS7Padding", accessKey.getBytes(), accessSecret.getBytes());
+        String tokenObj = aes.decryptStr(token);
+        return JSONObject.parseObject(tokenObj);
+    }
+}

+ 20 - 0
dmp-comp/dmp-auth/src/main/java/com/persagy/dmp/auth/service/impl/EmsAuthServiceImpl.java

@@ -0,0 +1,20 @@
+package com.persagy.dmp.auth.service.impl;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * 运维平台2.0 鉴权实现类
+ * 从head中获取上下文信息,并校验集团、项目是否有效
+ * @author Charlie Yu
+ * @date 2021-11-02
+ */
+public class EmsAuthServiceImpl extends AbstractAuthServiceImpl {
+
+    @Override
+    public void loginSuccess(HttpServletRequest request, HttpServletResponse response) {
+        super.loginSuccess(request, response);
+        loadContextByRequest(request);
+        // TODO 验证集团是否有效、验证项目是否匹配集团、没有集团编码时根据项目匹配集团
+    }
+}

+ 19 - 0
dmp-comp/dmp-auth/src/main/java/com/persagy/dmp/auth/service/impl/NoneAuthServiceImpl.java

@@ -0,0 +1,19 @@
+package com.persagy.dmp.auth.service.impl;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * 不鉴权 实现类
+ * 直接从head中获取上下文信息
+ * @author Charlie Yu
+ * @date 2021-11-02
+ */
+public class NoneAuthServiceImpl extends AbstractAuthServiceImpl{
+
+    @Override
+    public void loginSuccess(HttpServletRequest request, HttpServletResponse response) {
+        super.loginSuccess(request, response);
+        loadContextByRequest(request);
+    }
+}

+ 1 - 0
dmp-comp/pom.xml

@@ -18,5 +18,6 @@
         <module>dmp-file-starter</module>
         <module>dmp-digital-starter</module>
         <module>dmp-amqp-starter</module>
+        <module>dmp-auth</module>
     </modules>
 </project>

+ 5 - 0
dmp-parent/pom.xml

@@ -96,6 +96,11 @@
             </dependency>
             <dependency>
                 <groupId>com.persagy</groupId>
+                <artifactId>dmp-auth</artifactId>
+                <version>${dmp.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.persagy</groupId>
                 <artifactId>integrated-common-core</artifactId>
                 <version>${platform.version}</version>
             </dependency>

+ 1 - 2
dmp-server/pom.xml

@@ -30,8 +30,7 @@
         </dependency>
         <dependency>
             <groupId>com.persagy</groupId>
-            <artifactId>integrated-log-spring-boot-starter</artifactId>
-            <version>1.0.0</version>
+            <artifactId>dmp-auth</artifactId>
         </dependency>
     </dependencies>
 </project>