From 3520e86e2b00b9c1ee3f4fffd4ab49fe3d6c259e Mon Sep 17 00:00:00 2001
From: 黎星凯 <13949086503@163.com>
Date: 星期五, 17 五月 2024 15:29:21 +0800
Subject: [PATCH] 20240517修改: 关联源模块

---
 iplatform-base-security-consum/src/test/java/com/iplatform/security/TestSecurity.java                            |   37 
 iplatform-base-security-consum/src/main/java/com/iplatform/security/DefaultUserDetails.java                      |  171 +++
 iplatform-base-security-consum/src/main/java/com/iplatform/security/DefaultAuthenticationFailureHandler.java     |   59 +
 iplatform-base-security-consum/src/main/java/com/iplatform/security/JwtAuthenticationTokenFilter.java            |  195 +++
 iplatform-base-security-consum/src/main/java/com/iplatform/security/util/MockPrincipalUtils.java                 |   53 
 iplatform-base-security-consum/src/main/java/com/iplatform/security/DefaultAuthenticationSuccessHandler.java     |   38 
 iplatform-base-security-consum/src/main/java/com/iplatform/security/FailedAuthenticationEntryPoint.java          |   36 
 iplatform-base-security-consum/src/main/java/com/iplatform/security/controller/SecurityController.java           |  439 +++++++
 iplatform-base-security-consum/src/main/java/com/iplatform/security/exception/PcUserStopAppException.java        |   20 
 pom.xml                                                                                                          |    7 
 deploy-jar-single/src/main/resources/application.yml                                                             |    2 
 iplatform-base-security-consum/src/main/java/com/iplatform/security/DefaultAuthenticationProvider.java           |   99 +
 iplatform-base-security-consum/src/main/java/com/iplatform/security/DefaultSecuritySpi.java                      |  397 +++++++
 iplatform-base-security-consum/src/main/java/com/iplatform/security/callback/NoneCaptchaLoginCallback.java       |   11 
 iplatform-base-security-consum/src/main/java/com/iplatform/security/DefaultUserDetailsService.java               |  209 +++
 iplatform-base-security-consum/src/main/java/com/iplatform/security/util/ResourceLoaderUtils.java                |    5 
 iplatform-base-security-consum/src/main/java/com/iplatform/security/util/LoginCallbackUtils.java                 |   69 +
 iplatform-base-security-consum/src/main/java/com/iplatform/security/config/WebSecurityConfig.java                |  492 ++++++++
 iplatform-base-security-consum/src/main/java/com/iplatform/security/util/SecurityConfigUtils.java                |   58 +
 iplatform-base-security-consum/src/main/java/com/iplatform/security/DefaultLogoutSuccessHandler.java             |   81 +
 admin-web/public/static/config.js                                                                                |    8 
 iplatform-base-security-consum/src/main/java/com/iplatform/security/callback/SmsCodeLoginCallback.java           |   76 +
 iplatform-base-security-consum/src/main/java/com/iplatform/security/DefaultResourceLoaderProvider.java           |  257 ++++
 consum-base/pom.xml                                                                                              |    2 
 iplatform-base-security-consum/pom.xml                                                                           |   49 
 iplatform-base-security-consum/src/main/java/com/iplatform/security/event/RoleSecurityUpdateListener.java        |   40 
 iplatform-base-security-consum/src/main/java/com/iplatform/security/callback/ThirdPartyLoginCallback.java        |   33 
 iplatform-base-security-consum/src/main/java/com/iplatform/security/config/SecurityProperties.java               |  172 +++
 iplatform-base-security-consum/src/main/java/com/iplatform/security/callback/SimplePasswordLoginCallback.java    |   39 
 iplatform-base-security-consum/src/main/java/com/iplatform/security/callback/MobilePassCaptchaLoginCallback.java |   31 
 iplatform-base-security-consum/src/main/java/com/iplatform/security/callback/EncryptPasswordLoginCallback.java   |   57 +
 iplatform-base-security-consum/src/main/java/com/iplatform/security/DefaultAuthenticationFilter.java             |   35 
 iplatform-base-security-consum/src/main/java/com/iplatform/security/callback/WechatLoginCallback.java            |   34 
 iplatform-base-security-consum/src/main/java/com/iplatform/security/DefaultAuthenticationToken.java              |   31 
 34 files changed, 3,336 insertions(+), 6 deletions(-)

diff --git a/admin-web/public/static/config.js b/admin-web/public/static/config.js
index 77b3c75..3e156e6 100644
--- a/admin-web/public/static/config.js
+++ b/admin-web/public/static/config.js
@@ -9,8 +9,8 @@
 
 
   // 鎺ュ彛璇锋眰鍦板潃
-  ftpUrl: 'http://172.16.20.9:8083/lowConsum',//寮�鍙�
-  apiBaseURL: 'http://172.16.20.9:8083/lowConsum',//寮�鍙�
+  // ftpUrl: 'http://172.16.20.9:8083/lowConsum',//寮�鍙�
+  // apiBaseURL: 'http://172.16.20.9:8083/lowConsum',//寮�鍙�
 
 
   // apiBaseURL: 'http://172.16.60.110:8083/lowConsum',//寮�鍙�
@@ -20,8 +20,8 @@
   // apiBaseURL: protocol + '//'+ host + '/lowapi',// 姝e紡,
 
 
-  // ftpUrl: protocol + '//'+ host + '/lowapi',// 姝e紡,
-  // apiBaseURL: protocol + '//'+ host + '/lowapi',// 姝e紡,
+  ftpUrl: protocol + '//'+ host + '/lowapi',// 姝e紡,
+  apiBaseURL: protocol + '//'+ host + '/lowapi',// 姝e紡,
 
   debug: false //璋冭瘯寮�鍏�  true鏃朵細杈撳嚭璇锋眰鏃ュ織
 };
diff --git a/consum-base/pom.xml b/consum-base/pom.xml
index 0edc9dd..8c0f307 100644
--- a/consum-base/pom.xml
+++ b/consum-base/pom.xml
@@ -39,7 +39,7 @@
         <!-- 寮曞叆web瀹夊叏璁よ瘉妯″潡锛屽鏋滀笉寮曞叆鍒欎笉浼氬仛浠讳綍鏉冮檺鎷︽埅锛堣繖绉嶆ā寮忛�氬父鍙敤浜庡揩閫熸祴璇曪級, 2022/10/31 -->
         <dependency>
             <groupId>com.iplatform</groupId>
-            <artifactId>iplatform-base-security</artifactId>
+            <artifactId>iplatform-base-security-consum</artifactId>
             <exclusions>
                 <exclusion>
                     <artifactId>spring-security-crypto</artifactId>
diff --git a/deploy-jar-single/src/main/resources/application.yml b/deploy-jar-single/src/main/resources/application.yml
index a17ec4c..fadf7d2 100644
--- a/deploy-jar-single/src/main/resources/application.yml
+++ b/deploy-jar-single/src/main/resources/application.yml
@@ -1,4 +1,4 @@
 spring:
   profiles:
-    active: test
+    active: prod
 
diff --git a/iplatform-base-security-consum/pom.xml b/iplatform-base-security-consum/pom.xml
new file mode 100644
index 0000000..219ab9a
--- /dev/null
+++ b/iplatform-base-security-consum/pom.xml
@@ -0,0 +1,49 @@
+<?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>iplatform</artifactId>
+        <groupId>com.iplatform</groupId>
+        <version>2.3.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>iplatform-base-security-consum</artifactId>
+    <packaging>jar</packaging>
+    <version>1.0.0-SNAPSHOT</version>
+
+    <properties>
+    </properties>
+
+    <!--
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+    ~ WEB瀹夊叏妯″潡渚濊禆 iplatform-base锛屼綔涓轰竴涓彲閫夋敮鎸佹ā鍧椼��
+    ~ 涓氬姟搴旂敤濡傛灉闇�瑕佸紩鍏ヨ妯″潡鍗冲彲锛屽鏋滀娇鐢� gateway 妯″紡鍒欐棤闇�浣跨敤璇ユā鍧椼��
+    ~ 2022-10-26
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+     -->
+    <dependencies>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <!-- 閫氳繃鍩虹搴撳紩鍏�: spring-security, 2022/10/31 -->
+        <dependency>
+            <groupId>com.walkersoft</groupId>
+            <artifactId>walker-web-security</artifactId>
+        </dependency>
+
+        <!-- 骞冲彴鍩虹妯″潡蹇呴』瀛樺湪, 2022/10/31 -->
+        <dependency>
+            <groupId>com.iplatform</groupId>
+            <artifactId>iplatform-base</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+    </dependencies>
+
+</project>
diff --git a/iplatform-base-security-consum/src/main/java/com/iplatform/security/DefaultAuthenticationFailureHandler.java b/iplatform-base-security-consum/src/main/java/com/iplatform/security/DefaultAuthenticationFailureHandler.java
new file mode 100644
index 0000000..8f0ba15
--- /dev/null
+++ b/iplatform-base-security-consum/src/main/java/com/iplatform/security/DefaultAuthenticationFailureHandler.java
@@ -0,0 +1,59 @@
+package com.iplatform.security;
+
+import com.iplatform.security.exception.PcUserStopAppException;
+import com.walker.infrastructure.utils.JsonUtils;
+import com.walker.web.ResponseCode;
+import com.walker.web.ResponseValue;
+import com.walker.web.util.ServletUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.authentication.AccountExpiredException;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.authentication.CredentialsExpiredException;
+import org.springframework.security.authentication.DisabledException;
+import org.springframework.security.authentication.InternalAuthenticationServiceException;
+import org.springframework.security.authentication.LockedException;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.authentication.AuthenticationFailureHandler;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+public class DefaultAuthenticationFailureHandler implements AuthenticationFailureHandler {
+
+    protected final transient Logger logger = LoggerFactory.getLogger(getClass());
+
+    @Override
+    public void onAuthenticationFailure(HttpServletRequest request
+            , HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
+        String message = null;  //鎻愮ず淇℃伅
+        int code = ResponseCode.USER_CREDENTIALS_ERROR.getCode();         //閿欒缂栫爜
+
+        if(exception instanceof AccountExpiredException){
+            message = ResponseCode.USER_ACCOUNT_EXPIRED.getMessage();
+            logger.debug("---------> " + message);
+        }else if(exception instanceof BadCredentialsException){
+            message = ResponseCode.USER_CREDENTIALS_ERROR.getMessage();
+        }else if(exception instanceof CredentialsExpiredException){
+            message = "瀵嗙爜杩囨湡,鐧诲綍澶辫触锛�";
+        }else if(exception instanceof DisabledException){
+            message = ResponseCode.USER_ACCOUNT_DISABLE.getMessage();
+        }else if(exception instanceof LockedException){
+            message = ResponseCode.USER_ACCOUNT_LOCKED.getMessage();
+        }else if(exception instanceof InternalAuthenticationServiceException){
+            message = ResponseCode.USER_CREDENTIALS_ERROR.getMessage();
+        }else if(exception instanceof PcUserStopAppException){
+            message = PcUserStopAppException.MESSAGE;
+        }else{
+            message = "鐧诲綍澶辫触锛�";
+        }
+
+        try {
+            ServletUtils.renderString(response, JsonUtils.objectToJsonString(ResponseValue.error(message)));
+        } catch (Exception e) {
+            logger.error("璁よ瘉澶辫触:" + request.getRequestURI(), e);
+        }
+    }
+}
diff --git a/iplatform-base-security-consum/src/main/java/com/iplatform/security/DefaultAuthenticationFilter.java b/iplatform-base-security-consum/src/main/java/com/iplatform/security/DefaultAuthenticationFilter.java
new file mode 100644
index 0000000..7748085
--- /dev/null
+++ b/iplatform-base-security-consum/src/main/java/com/iplatform/security/DefaultAuthenticationFilter.java
@@ -0,0 +1,35 @@
+package com.iplatform.security;
+
+import org.springframework.security.authentication.AuthenticationServiceException;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * DefaultAuthenticationToken 閲嶅啓鍚庯紝鐧诲綍鎬绘槸鎶ラ敊: 鐢ㄦ埛鍚嶆垨瀵嗙爜閿欒锛屽皾璇曢噸鍐欒杩囨护鍣ㄣ��
+ * @author 鏃跺厠鑻�
+ * @date 2023-01-27
+ */
+@Deprecated
+public class DefaultAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
+
+    @Override
+    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
+//        if (this.postOnly && !request.getMethod().equals("POST")) {
+        if (!request.getMethod().equals("POST")) {
+            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
+        } else {
+            String username = this.obtainUsername(request);
+            username = username != null ? username.trim() : "";
+            String password = this.obtainPassword(request);
+            password = password != null ? password : "";
+//            UsernamePasswordAuthenticationToken authRequest = UsernamePasswordAuthenticationToken.unauthenticated(username, password);
+            DefaultAuthenticationToken authRequest = (DefaultAuthenticationToken)DefaultAuthenticationToken.unauthenticated(username, password);
+            this.setDetails(request, authRequest);
+            return this.getAuthenticationManager().authenticate(authRequest);
+        }
+    }
+}
diff --git a/iplatform-base-security-consum/src/main/java/com/iplatform/security/DefaultAuthenticationProvider.java b/iplatform-base-security-consum/src/main/java/com/iplatform/security/DefaultAuthenticationProvider.java
new file mode 100644
index 0000000..9231170
--- /dev/null
+++ b/iplatform-base-security-consum/src/main/java/com/iplatform/security/DefaultAuthenticationProvider.java
@@ -0,0 +1,99 @@
+package com.iplatform.security;
+
+import com.iplatform.base.PlatformLoginCallback;
+import com.iplatform.base.pojo.RequestLogin;
+import com.iplatform.security.exception.PcUserStopAppException;
+import com.iplatform.security.util.LoginCallbackUtils;
+import com.walker.web.CaptchaType;
+import com.walker.web.ClientType;
+import com.walker.web.LoginType;
+import com.walker.web.ResponseCode;
+import com.walker.web.UserType;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.authentication.InternalAuthenticationServiceException;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+
+/**
+ * 鑷畾涔夎璇佹彁渚涜�咃紝鐢卞钩鍙拌嚜宸卞喅瀹氬浣曞姣斿瘑鐮侀獙璇侊紝濡傛灉涓嶅畾鍒跺垯spring浼氳嚜鍔ㄦ瘮杈冨瘑鐮併��
+ * @author 鏃跺厠鑻�
+ * @date 2023-01-28
+ */
+public class DefaultAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
+
+    @Override
+    protected void additionalAuthenticationChecks(UserDetails userDetails
+            , UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
+        if(!(authentication instanceof DefaultAuthenticationToken)){
+            throw new InternalAuthenticationServiceException("UsernamePasswordAuthenticationToken 蹇呴』鏄�: DefaultAuthenticationToken", null);
+        }
+        DefaultAuthenticationToken defaultAuthenticationToken = (DefaultAuthenticationToken)authentication;
+        RequestLogin requestLogin = defaultAuthenticationToken.getRequestLogin();
+
+        // 闈濧PP鐢ㄦ埛鑳藉惁鐧诲綍鎵嬫満APP锛熷彲浠ュ湪杩欓噷鍒ゆ柇锛�2023-03-20
+        if(!this.allowPcUserAccessApp){
+            if(requestLogin.getClientType().equalsIgnoreCase(ClientType.MOBILE.getIndex())){
+                DefaultUserDetails defaultUserDetails = (DefaultUserDetails) userDetails;
+                if(defaultUserDetails.getUserPrincipal().getUserInfo().getUser_type() != UserType.TYPE_APP_REG){
+                    // 鐧诲綍鏂瑰紡涓虹Щ鍔ㄧ锛屽悓鏃剁敤鎴风被鍒负闈瀉pp鐢ㄦ埛锛岀姝㈢櫥褰�
+                    throw new PcUserStopAppException(null);
+                }
+            }
+        }
+
+        // 閫氳繃鐧诲綍绫诲瀷锛岃幏鍙栭厤缃殑鐧诲綍鍥炶皟瀵硅薄锛屽娲惧疄鐜板瘑鐮侀獙璇併��
+        // 2023-12-28 绉诲姩绔櫥褰曢獙璇�
+        CaptchaType captchaType = CaptchaType.getType(requestLogin.getVerifyType());
+        PlatformLoginCallback loginCallback = LoginCallbackUtils.getLoginCallbackBean(LoginType.getType(requestLogin.getLoginType()), true, captchaType);
+        if(loginCallback == null){
+            throw new InternalAuthenticationServiceException("loginCallback鏈壘鍒�:" + requestLogin.getLoginType());
+        }
+        boolean success = loginCallback.validatePassword(((DefaultUserDetails)userDetails).getUserPrincipal());
+        if(!success){
+            throw new BadCredentialsException(ResponseCode.USER_CREDENTIALS_ERROR.getMessage());
+        }
+        logger.debug("++++++++++++ 鑷姩楠岃瘉瀵嗙爜涓烘纭�, loginType = " + requestLogin.getLoginType());
+    }
+
+    @Override
+    protected UserDetails retrieveUser(String username
+            , UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
+        try{
+            UserDetails loadedUser = this.userDetailsService.loadUserByUsername(username);
+            if(loadedUser == null){
+                throw new InternalAuthenticationServiceException("UserDetailsService returned null, which is an interface contract violation");
+            }
+            return loadedUser;
+
+        } catch (Exception ex){
+            if(ex instanceof UsernameNotFoundException){
+                logger.debug("+++++++++++++++ " + ex.getMessage());
+                throw ex;
+            }
+            if(ex instanceof InternalAuthenticationServiceException){
+                throw ex;
+            }
+            throw new InternalAuthenticationServiceException(ex.getMessage(), ex);
+        }
+    }
+
+    public void setUserDetailsService(UserDetailsService userDetailsService) {
+        this.userDetailsService = userDetailsService;
+    }
+
+    /**
+     * 璁剧疆鏄惁鍏佽'鍚庡彴PC鐢ㄦ埛'璁块棶鐧诲綍鎵嬫満APP
+     * @param allowPcUserAccessApp
+     * @date 2023-03-20
+     */
+    public void setAllowPcUserAccessApp(boolean allowPcUserAccessApp) {
+        this.allowPcUserAccessApp = allowPcUserAccessApp;
+    }
+
+    private boolean allowPcUserAccessApp = true;
+    private UserDetailsService userDetailsService;
+}
diff --git a/iplatform-base-security-consum/src/main/java/com/iplatform/security/DefaultAuthenticationSuccessHandler.java b/iplatform-base-security-consum/src/main/java/com/iplatform/security/DefaultAuthenticationSuccessHandler.java
new file mode 100644
index 0000000..6ddd13d
--- /dev/null
+++ b/iplatform-base-security-consum/src/main/java/com/iplatform/security/DefaultAuthenticationSuccessHandler.java
@@ -0,0 +1,38 @@
+package com.iplatform.security;
+
+import com.walker.web.TokenGenerator;
+import com.walker.web.UserPrincipal;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+@Deprecated
+public class DefaultAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
+
+    protected final transient Logger logger = LoggerFactory.getLogger(getClass());
+
+    private TokenGenerator tokenGenerator;
+
+    public void setTokenGenerator(TokenGenerator tokenGenerator) {
+        this.tokenGenerator = tokenGenerator;
+    }
+
+    @Override
+    public void onAuthenticationSuccess(HttpServletRequest request
+            , HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
+
+        // 1.鑾峰彇閫氳繃璁よ瘉鐢ㄦ埛瀵硅薄
+        // 2.鐢熸垚Token淇℃伅
+        // 3.鍏宠仈Token涓庣敤鎴蜂俊鎭紝骞跺瓨鍌ㄥ埌缂撳瓨(鍐呭瓨)涓�
+        // 4.杩斿洖瀹㈡埛绔�:鐢ㄦ埛浠ュ強Token
+        logger.info("onAuthenticationSuccess = " + authentication.getPrincipal());
+        UserPrincipal userPrincipal = (UserPrincipal) authentication.getPrincipal();
+
+    }
+}
diff --git a/iplatform-base-security-consum/src/main/java/com/iplatform/security/DefaultAuthenticationToken.java b/iplatform-base-security-consum/src/main/java/com/iplatform/security/DefaultAuthenticationToken.java
new file mode 100644
index 0000000..1301381
--- /dev/null
+++ b/iplatform-base-security-consum/src/main/java/com/iplatform/security/DefaultAuthenticationToken.java
@@ -0,0 +1,31 @@
+package com.iplatform.security;
+
+import com.iplatform.base.pojo.RequestLogin;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+
+/**
+ * 閲嶅啓榛樿鐨勮璇乼oken瀵硅薄锛屾坊鍔犺嚜瀹氫箟灞炴�с��
+ * @author 鏃跺厠鑻�
+ * @date 2023-01-27
+ */
+public class DefaultAuthenticationToken extends UsernamePasswordAuthenticationToken {
+
+    private RequestLogin requestLogin;
+
+    /**
+     * 杩斿洖璇锋眰鐧诲綍鎻愪氦鐨勫師濮嬫暟鎹�
+     * @return
+     */
+    public RequestLogin getRequestLogin() {
+        return requestLogin;
+    }
+
+    public DefaultAuthenticationToken(Object principal, Object credentials) {
+        super(principal, credentials);
+    }
+
+    public DefaultAuthenticationToken(Object principal, Object credentials, RequestLogin requestLogin){
+        super(principal, credentials);
+        this.requestLogin = requestLogin;
+    }
+}
diff --git a/iplatform-base-security-consum/src/main/java/com/iplatform/security/DefaultLogoutSuccessHandler.java b/iplatform-base-security-consum/src/main/java/com/iplatform/security/DefaultLogoutSuccessHandler.java
new file mode 100644
index 0000000..fd565cd
--- /dev/null
+++ b/iplatform-base-security-consum/src/main/java/com/iplatform/security/DefaultLogoutSuccessHandler.java
@@ -0,0 +1,81 @@
+package com.iplatform.security;
+
+import com.iplatform.base.UserLoginCache;
+import com.iplatform.base.VariableConstants;
+import com.iplatform.base.callback.AfterLoginCallback;
+import com.iplatform.base.callback.PlatformCallbackPostProcessor;
+import com.iplatform.base.util.TokenUtils;
+import com.walker.infrastructure.utils.StringUtils;
+import com.walker.web.ResponseValue;
+import com.walker.web.TokenException;
+import com.walker.web.TokenGenerator;
+import com.walker.web.UserOnlineProvider;
+import com.walker.web.util.ServletUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+public class DefaultLogoutSuccessHandler implements LogoutSuccessHandler {
+
+    protected final transient Logger logger = LoggerFactory.getLogger(getClass());
+
+    private UserOnlineProvider userOnlineProvider;
+
+    private TokenGenerator tokenGenerator;
+
+    private UserLoginCache userLoginCache;
+
+    public void setUserLoginCache(UserLoginCache userLoginCache) {
+        this.userLoginCache = userLoginCache;
+    }
+
+    public void setTokenGenerator(TokenGenerator tokenGenerator) {
+        this.tokenGenerator = tokenGenerator;
+    }
+
+    public void setUserOnlineProvider(UserOnlineProvider userOnlineProvider) {
+        this.userOnlineProvider = userOnlineProvider;
+    }
+
+    @Override
+    public void onLogoutSuccess(HttpServletRequest request
+            , HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
+        String token = TokenUtils.getAuthorizationToken(request);
+        if(StringUtils.isNotEmpty(token)){
+            try{
+                String data = tokenGenerator.validateToken(token, VariableConstants.TOKEN_SECRET);
+                String[] userIdAndKey = TokenUtils.getUserIdAndKey(data);
+                this.userOnlineProvider.removeUserPrincipal(userIdAndKey[2]);
+                // 2023-07-11 鐢ㄦ埛鐧诲綍绛栫暐缂撳瓨涔熷垹闄�
+                this.userLoginCache.removeUserLogin(userIdAndKey[1]);
+
+                // 2023-08-18锛岀櫥褰曟垚鍔熷洖璋�
+                AfterLoginCallback afterLoginCallback = PlatformCallbackPostProcessor.getCallbackObject(AfterLoginCallback.class);
+                if(afterLoginCallback != null){
+                    afterLoginCallback.onLogout(userIdAndKey[1]);
+                }
+
+                logger.debug("鐢ㄦ埛 logout success: " + userIdAndKey[1]);
+            } catch (TokenException ex){
+                logger.error("logout娉ㄩ攢鏃讹紝token瑙f瀽閿欒:" + ex.getMessage() + ", token=" + token, ex);
+                if(ex.isExpired()){
+                    this.recordLogoutInfo("null", "logout", "token瓒呮椂锛岄��鍑烘搷浣滄棤娉曞垹闄ょ紦瀛�");
+                } else {
+                    this.recordLogoutInfo("null", "logout", "token瓒呮椂锛岄��鍑烘搷浣滃紓甯�:" + ex.getMessage());
+                }
+            }
+        }
+        ServletUtils.renderString(response, ResponseValue.success("閫�鍑烘垚鍔�"));
+    }
+
+    private void recordLogoutInfo(String loginId, String status, String message){
+        logger.debug("寮傛璁板綍閫�鍑烘棩蹇楋紝鍚庣画瑕佽ˉ鍏�:" + status + ", " + message);
+    }
+
+}
diff --git a/iplatform-base-security-consum/src/main/java/com/iplatform/security/DefaultResourceLoaderProvider.java b/iplatform-base-security-consum/src/main/java/com/iplatform/security/DefaultResourceLoaderProvider.java
new file mode 100644
index 0000000..f7bd564
--- /dev/null
+++ b/iplatform-base-security-consum/src/main/java/com/iplatform/security/DefaultResourceLoaderProvider.java
@@ -0,0 +1,257 @@
+package com.iplatform.security;
+
+import com.iplatform.base.SecurityConstants;
+import com.iplatform.base.cache.MenuCacheProvider;
+import com.walker.infrastructure.utils.StringUtils;
+import com.walker.web.Constants;
+import com.walker.web.security.ResourceLoadProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.access.ConfigAttribute;
+import org.springframework.security.access.SecurityConfig;
+import org.springframework.security.web.FilterInvocation;
+import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * 榛樿璧勬簮鍔犺浇鎻愪緵鑰咃紝security妗嗘灦闇�瑕佺殑鏉冮檺鐐归泦鍚堛��
+ * @author 鏃跺厠鑻�
+ * @date 2022-11-02
+ */
+public class DefaultResourceLoaderProvider implements ResourceLoadProvider {
+
+    protected final transient Logger logger = LoggerFactory.getLogger(getClass());
+
+    private MenuCacheProvider menuCacheProvider = null;
+
+    private Map<String, Collection<ConfigAttribute>> resultMap = new HashMap<String, Collection<ConfigAttribute>>();
+
+    /** 璇锋眰鍖归厤瀵硅薄鏀惧叆Map涓紝閬垮厤閲嶅鍒涘缓銆俴ey = url锛寁alue = AntPathRequestMatcher */
+    private Map<String, AntPathRequestMatcher> requestMatchers = new ConcurrentHashMap<String, AntPathRequestMatcher>();
+
+    private Collection<ConfigAttribute> emptyAttributes = null;
+    private Collection<ConfigAttribute> anonymousAttributes = null;
+    // 2023-03-21 activiti7宸ヤ綔娴佸繀椤绘嫤鎴潈闄愶紝鍙樻�併��
+    private Collection<ConfigAttribute> activiti7Attributes = null;
+
+    private List<String> permitAccessUrls = null;
+
+    private Map<String, String> anonymousUrlMap = null;
+
+    /**
+     * 璁剧疆鍙尶鍚嶈闂殑鍏紑鍦板潃闆嗗悎锛屽: ["/login","/register", "/image/**"]
+     * @param anonymousUrlList
+     */
+    public void setAnonymousUrlList(List<String> anonymousUrlList) {
+        if(!StringUtils.isEmptyList(anonymousUrlList)){
+            this.anonymousUrlMap = new HashMap<>();
+            for(String url : anonymousUrlList){
+                this.anonymousUrlMap.put(url, StringUtils.EMPTY_STRING);
+            }
+        }
+    }
+
+    /**
+     * 璁剧疆涓�浜涘彧瑕佽璇佺敤鎴烽兘鍙互璁块棶鐨勫父鐢╱rl锛屽: /api/**, /report/** 绛�
+     * @param permitAccessUrls
+     */
+    public void setPermitAccessUrls(List<String> permitAccessUrls) {
+        this.permitAccessUrls = permitAccessUrls;
+    }
+
+    public void setMenuCacheProvider(MenuCacheProvider menuCacheProvider) {
+        this.menuCacheProvider = menuCacheProvider;
+    }
+
+    @Override
+    public Map<String, Collection<ConfigAttribute>> loadResource() {
+        resultMap.clear();
+        requestMatchers.clear();
+
+        // 1-鎶婅彍鍗曞拰鍔熻兘鐐箄rl瑙掕壊鍏崇郴鏁寸悊鍒板璞′腑锛歶rlRoleMap
+        Map<String, List<String>> urlRoleMap = new HashMap<String, List<String>>();
+
+        // 2-鎵�鏈夎鑹插搴旂殑URL閮藉姞鍏�
+        List<String[]> roleUrlMap = this.menuCacheProvider.getAllRoleMenuMap();
+        if(roleUrlMap != null && roleUrlMap.size() > 0){
+            String url = null;
+            for(String[] entry : roleUrlMap){
+                url = entry[1];
+                if(StringUtils.isEmpty(url)){
+                    throw new NullPointerException("url is not null! role = " + entry[0]);
+                }
+                setUrlRoleMap(urlRoleMap, url, entry[0]);
+            }
+        }
+
+        // 3-瓒呯骇绠$悊鍛橀粯璁ゅ姞涓婃墍鏈夎彍鍗曟潈闄�
+        List<String> allMenuUrl = this.menuCacheProvider.getAllMenuUrlList();
+        if(!StringUtils.isEmptyList(allMenuUrl)){
+            for(String url : allMenuUrl){
+                setUrlRoleMap(urlRoleMap, url, SecurityConstants.ROLE_SUPER_ADMIN);
+            }
+        }
+        setUrlRoleMap(urlRoleMap, "/supervisor/**", SecurityConstants.ROLE_SUPER_ADMIN);
+//        setUrlRoleMap(urlRoleMap, "/wf/**", SecurityConstants.ROLE_SUPER_ADMIN);
+
+        // 4-鎵�鏈夊凡鐧诲綍鐢ㄦ埛锛岄兘鍙互璁块棶榛樿鍏紑鍦板潃: /permit
+        setUrlRoleMap(urlRoleMap, "/permit/**", SecurityConstants.ROLE_USER);
+
+        // 5-鍏朵粬涓�浜涘彲鐢ㄥ湴鍧�锛屽凡璁よ瘉鐢ㄦ埛閮藉彲浠ヨ闂紝鏃犻渶鍗曠嫭閰嶇疆鏉冮檺
+        if(!StringUtils.isEmptyList(this.permitAccessUrls)){
+            for(String url : this.permitAccessUrls){
+                setUrlRoleMap(urlRoleMap, url, SecurityConstants.ROLE_USER);
+//                logger.debug("鍏叡璁块棶璧勬簮锛�" + url);
+//                logger.debug(urlRoleMap.toString());
+          }
+        }
+
+        // 6-鍖垮悕URL涓嶆嫤鎴�
+        if(this.anonymousUrlMap != null){
+            for(String url : this.anonymousUrlMap.keySet()){
+                setUrlRoleMap(urlRoleMap, url, Constants.ROLE_ANONYMOUS);
+            }
+        }
+
+        // 7-activiti7宸ヤ綔娴佹潈闄愶紝蹇呴』鍔犱笂銆�2023-03-21
+        this.setUrlRoleMap(urlRoleMap, "/wf/**", Constants.ROLE_ACTIVITI_USER);
+
+        logger.info("鍏卞姞杞芥潈闄愮偣: " + urlRoleMap.size());
+//        if(logger.isDebugEnabled()){
+//            for(Map.Entry<String, List<String>> entry : urlRoleMap.entrySet()){
+//                logger.debug(entry.getKey() + " = " + entry.getValue());
+//            }
+//        }
+
+        // 6-杞垚spring security 鐗瑰畾鏉冮檺灞炴��
+        if(urlRoleMap.size() > 0){
+            List<ConfigAttribute> caList = null;
+            for(Map.Entry<String, List<String>> entry : urlRoleMap.entrySet()){
+                caList = new ArrayList<ConfigAttribute>(entry.getValue().size()+1);
+                for(String s : entry.getValue()){
+                    ConfigAttribute ca = new SecurityConfig(s);
+                    caList.add(ca);
+                }
+                resultMap.put(entry.getKey(), caList);
+            }
+        }
+
+        // 7-鍒濆鍖栬姹傝矾寰勫尮閰嶆牎楠屽璞�
+        Iterator<String> it = resultMap.keySet().iterator();
+        String resURL = null;
+        AntPathRequestMatcher requestMatcher = null;
+        while(it.hasNext()){
+            resURL = it.next();
+            requestMatcher = requestMatchers.get(resURL);
+            // 鎶妑equestMatcher瀵硅薄鏀惧埌Map涓紝閬垮厤閲嶅鍒涘缓
+            if(requestMatcher == null){
+                requestMatcher = new AntPathRequestMatcher(resURL);
+                requestMatchers.put(resURL, requestMatcher);
+            }
+        }
+        return resultMap;
+    }
+
+    @Override
+    public void reloadResource() {
+        this.loadResource();
+        logger.info("ResourceLoaderProvider reload success!");
+    }
+
+    @Override
+    public Collection<ConfigAttribute> getAttributes(Object object) {
+        if(resultMap == null) return getEmptyAttributes();
+
+        Iterator<String> it = resultMap.keySet().iterator();
+
+        String srcURL = null;
+        String resURL = null;
+        AntPathRequestMatcher requestMatcher = null;
+
+        while(it.hasNext()){
+            resURL = it.next();
+            requestMatcher = requestMatchers.get(resURL);
+            // 鎶妑equestMatcher瀵硅薄鏀惧埌Map涓紝閬垮厤閲嶅鍒涘缓
+            if(requestMatcher == null){
+                requestMatcher = new AntPathRequestMatcher(resURL);
+                requestMatchers.put(resURL, requestMatcher);
+            }
+            srcURL = ((FilterInvocation)object).getRequestUrl();
+            if(requestMatcher.matches(((FilterInvocation)object).getRequest())){
+                logger.debug("............> 鎵惧埌浜嗗尮閰嶇殑璧勬簮: " + resURL + ", 璇锋眰鐨勮祫婧�: " + srcURL);
+                // 2023-03-21 activiti7淇敼锛屽綋璁块棶娴佺▼鐩稿叧鍔熻兘锛岀粰浜堟祦绋嬩笓鐢ㄨ鑹�
+                // 杩欐槸activiti7鏈哄埗闇�瑕佺殑锛屽彉鎬侊紒
+                if(resURL.startsWith(SecurityConstants.URL_WORKFLOW_PREFIX)){
+                    logger.debug("杩斿洖activiti7鐨勮鑹查泦鍚�");
+                    return this.getActiviti7Attributes();
+                }
+                return resultMap.get(resURL);
+            }
+        }
+
+        // 2022-11-13
+        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+        // 濡傛灉閫氳繃琛ㄨ揪寮忔病鏈夊尮閰嶅埌URL锛岃繖閲岃妫�鏌ユ槸鍚﹀尶鍚嶈矾寰�
+        // 娉ㄦ剰锛氫笉鑳芥妸鍒ゆ柇鏀惧湪鍓嶉潰锛屽洜涓虹敤鎴烽厤缃尶鍚嶅湴鍧�鍙兘甯︽湁閫氶厤绗︼紝濡傦細/nano/**
+        // 浣嗘槸杩欓噷request鑾峰緱鐨刄RI鏄壒瀹氬湴鍧�锛屽: /nano/123
+        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+        if(this.anonymousUrlMap != null && this.anonymousUrlMap.get(srcURL) != null){
+            return this.getAnonymousAttributes();
+        }
+
+        // 濡傛灉鏍规嵁URL娌℃湁鎵惧埌瀵瑰簲鐨勮鑹查泦鍚堬紝灏辫繑鍥炰竴涓┖闆嗗悎锛�
+        // 鍥犱负spring security榛樿瀵逛簬绌洪泦鍚堥兘鏀捐銆�
+        return getEmptyAttributes();
+    }
+
+    @Override
+    public Collection<ConfigAttribute> getAttributesByUri(String uri) {
+        return null;
+    }
+
+    private void setUrlRoleMap(Map<String, List<String>> urlRoleMap, String _url, String _roleId){
+        List<String> _roles = urlRoleMap.get(_url);
+        if(_roles == null){
+            _roles = new ArrayList<String>(8);
+            _roles.add(_roleId);
+            urlRoleMap.put(_url, _roles);
+        } else if(!_roles.contains(_roleId)){
+            _roles.add(_roleId);
+        }
+    }
+
+    protected Collection<ConfigAttribute> getEmptyAttributes(){
+        if(emptyAttributes == null){
+            emptyAttributes = new ArrayList<ConfigAttribute>(2);
+            emptyAttributes.add(new SecurityConfig(Constants.ROLE_EMPTY));
+        }
+        return emptyAttributes;
+    }
+    protected Collection<ConfigAttribute> getAnonymousAttributes(){
+        if(anonymousAttributes == null){
+            anonymousAttributes = new ArrayList<ConfigAttribute>(2);
+            anonymousAttributes.add(new SecurityConfig(Constants.ROLE_ANONYMOUS));
+        }
+        return emptyAttributes;
+    }
+
+    /**
+     * 杩斿洖Activiti7闇�瑕佺殑瑙掕壊闆嗗悎銆�
+     * @return
+     * @date 2023-03-21
+     */
+    protected Collection<ConfigAttribute> getActiviti7Attributes(){
+        if(this.activiti7Attributes == null){
+            activiti7Attributes = new ArrayList<ConfigAttribute>(2);
+            activiti7Attributes.add(new SecurityConfig(Constants.ROLE_ACTIVITI_USER));
+        }
+        return this.activiti7Attributes;
+    }
+}
diff --git a/iplatform-base-security-consum/src/main/java/com/iplatform/security/DefaultSecuritySpi.java b/iplatform-base-security-consum/src/main/java/com/iplatform/security/DefaultSecuritySpi.java
new file mode 100644
index 0000000..fa01fd1
--- /dev/null
+++ b/iplatform-base-security-consum/src/main/java/com/iplatform/security/DefaultSecuritySpi.java
@@ -0,0 +1,397 @@
+package com.iplatform.security;
+
+import com.iplatform.base.ArgumentsConstants;
+import com.iplatform.base.AsyncManager;
+import com.iplatform.base.PlatformLoginCallback;
+import com.iplatform.base.SecurityConstants;
+import com.iplatform.base.SecuritySpi;
+import com.iplatform.base.VariableConstants;
+import com.iplatform.base.callback.AfterLoginCallback;
+import com.iplatform.base.callback.PlatformCallbackPostProcessor;
+import com.iplatform.base.config.LogProperties;
+import com.iplatform.base.exception.LoginException;
+import com.iplatform.base.pojo.RequestLogin;
+import com.iplatform.base.service.LogServiceImpl;
+import com.iplatform.base.service.LoginServiceImpl;
+import com.iplatform.base.support.strategy.LoginStrategyManager;
+import com.iplatform.base.util.TokenUtils;
+import com.iplatform.base.util.UserUtils;
+import com.iplatform.core.BeanContextAware;
+import com.iplatform.model.po.S_login_info;
+import com.iplatform.model.po.S_user_core;
+import com.iplatform.model.po.S_user_login;
+import com.iplatform.security.config.SecurityProperties;
+import com.iplatform.security.util.LoginCallbackUtils;
+import com.iplatform.security.util.SecurityConfigUtils;
+import com.walker.cache.CacheProvider;
+import com.walker.infrastructure.arguments.ArgumentsManager;
+import com.walker.infrastructure.arguments.Variable;
+import com.walker.infrastructure.utils.DateUtils;
+import com.walker.infrastructure.utils.NumberGenerator;
+import com.walker.infrastructure.utils.StringUtils;
+import com.walker.web.CaptchaProvider;
+import com.walker.web.CaptchaResult;
+import com.walker.web.CaptchaType;
+import com.walker.web.Constants;
+import com.walker.web.LoginType;
+import com.walker.web.ResponseCode;
+import com.walker.web.TokenGenerator;
+import com.walker.web.UserOnlineProvider;
+import com.walker.web.UserPrincipal;
+import com.walker.web.WebAgentService;
+import com.walker.web.WebRuntimeException;
+import com.walker.web.WebUserAgent;
+import com.walker.web.util.IdUtils;
+import com.walker.web.util.ServletUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.security.crypto.password.PasswordEncoder;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TimerTask;
+
+public class DefaultSecuritySpi implements SecuritySpi {
+
+    protected final transient Logger logger = LoggerFactory.getLogger(this.getClass());
+
+    public DefaultSecuritySpi(){}
+
+    @Override
+    public boolean isAllowMobileLoginRegister(){
+        return this.getSecurityProperties().isAllowMobileLoginReg();
+    }
+
+    @Override
+    public Map<String, Object> login(RequestLogin requestLogin) throws LoginException {
+        String username = requestLogin.getUsername();
+        // 2023-01-26 涓轰簡鏀寔澶氱鐧诲綍鏂瑰紡锛屼娇鐢ㄧ櫥褰曞洖璋冨鐞嗗叿浣撶櫥褰曠粏鑺傘��
+        // 2023-12-28 绉诲姩绔櫥褰曢獙璇�
+        CaptchaType captchaType = CaptchaType.getType(requestLogin.getVerifyType());
+        PlatformLoginCallback loginCallback = LoginCallbackUtils.getLoginCallbackBean(LoginType.getType(requestLogin.getLoginType()), true, captchaType);
+
+        boolean captchaEnabled = this.getArgumentVariable(ArgumentsConstants.KEY_SECURITY_CAPTCHA_ENABLED).getBooleanValue();
+        // 2023-01-26 杩欓噷APP绔槸涓嶉渶瑕侀獙璇佺爜鐨�
+        if(captchaEnabled){
+            CaptchaProvider<CaptchaResult> captchaProvider = loginCallback.getCaptchaProvider();
+            if(captchaProvider == null){
+//                return ResponseValue.error("绯荤粺闇�瑕侀獙璇佺爜锛屼絾鐧诲綍鏈厤缃�:" + loginCallback.getClass().getName());
+                throw new LoginException("绯荤粺闇�瑕侀獙璇佺爜锛屼絾鐧诲綍鏈厤缃�:" + loginCallback.getClass().getName());
+            }
+            if(StringUtils.isEmpty(requestLogin.getVerifyType())){
+//                return ResponseValue.error("璇锋眰閿欒锛氶獙璇佺爜绫诲瀷涓虹┖");
+                throw new LoginException("璇锋眰閿欒锛氶獙璇佺爜绫诲瀷涓虹┖");
+            }
+
+            // 绗笁鏂瑰鎺ョ殑璁よ瘉鐧诲綍锛屼笉闇�瑕佹娴嬮獙璇佺爜绫诲瀷鏄惁涓庡悗鍙颁竴鑷淬��2023-07-03
+            if(captchaProvider.getCaptchaType() != CaptchaType.ThirdParty
+                    && !requestLogin.getVerifyType().equals(captchaProvider.getCaptchaType().getIndex())){
+                throw new LoginException("鍓嶇閰嶇疆鐨勯獙璇佺爜绫诲瀷涓庡悗鍙颁笉涓�鑷�! verifyType = " + captchaProvider.getCaptchaType());
+            }
+            if(loginCallback.isValidateCaptcha()){
+                logger.debug("闇�瑕侀獙璇佺爜锛実etCaptchaType={}", loginCallback.getCaptchaProvider().getCaptchaType());
+                String error = this.validateCaptcha(requestLogin.getCode(), requestLogin.getUuid(), captchaProvider);
+                if(error != null){
+//                    return ResponseValue.error(error);
+                    throw new LoginException(error);
+                }
+            }
+        }
+
+        // 2023-07-11 妫�鏌ョ櫥褰曠瓥鐣ユ槸鍚︽弧瓒�
+        if(this.getLogProperties().isLoginEnabled()){
+            String error = this.getLoginStrategyManager().execute(requestLogin);
+            if(error != null){
+                throw new LoginException(error);
+            }
+        }
+
+        // 鐢ㄦ埛楠岃瘉
+        Authentication authentication = null;
+
+        try{
+//            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
+            DefaultAuthenticationToken authenticationToken = new DefaultAuthenticationToken(username, requestLogin.getPassword(), requestLogin);
+            // 杩欓噷鏀惧叆绾跨▼锛屽悗闈serDetailsService浼氫娇鐢�
+            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
+            authentication = this.getAuthenticationManager().authenticate(authenticationToken);
+
+        } catch (Exception e){
+            this.recordLoginInfo(requestLogin.getUsername(), String.valueOf(ResponseCode.ERROR.getCode()), "鐧诲綍鏈垚鍔熻璇�", 0, null, null);
+            if(e instanceof UsernameNotFoundException){
+//                throw new LoginException("鐢ㄦ埛璐﹀彿涓嶅瓨鍦紝鎴栧凡鍋滅敤锛�" + requestLogin.getUsername(), e, true);
+                throw new LoginException("鐢ㄦ埛璐﹀彿涓嶅瓨鍦紝鎴栧凡鍋滅敤锛�" + requestLogin.getUsername(), null, true);
+            }
+            if (e instanceof BadCredentialsException){
+//                return ResponseValue.error(ResponseCode.USER_CREDENTIALS_ERROR.getCode(), ResponseCode.USER_CREDENTIALS_ERROR.getMessage());
+                logger.debug("++++++++++++++++++ 瀵嗙爜閿欒");
+                throw new LoginException(ResponseCode.USER_CREDENTIALS_ERROR.getMessage());
+            } else {
+                // 2023-03-20
+                // 鐧诲綍楠岃瘉鎶涘嚭寮傚父锛屼細鍦ㄨ繖閲岀粺涓�澶勭悊锛屽锛歅cUserStopAppException銆�
+                // DefaultAuthenticationProvider
+//                return ResponseValue.error(ResponseCode.USER_CREDENTIALS_ERROR.getCode(), e.getMessage());
+                throw new LoginException(e.getMessage());
+            }
+        }
+
+        DefaultUserDetails userDetails = (DefaultUserDetails)authentication.getPrincipal();
+        if(this.logger.isDebugEnabled()){
+            logger.debug(userDetails.getUserPrincipal().toString());
+        }
+
+        // 2023-03-20锛屽浜庣┖楠岃瘉鐮佺被鍨嬶紙鐧诲綍鏂瑰紡锛夛紝闇�瑕佸悗鍙拌嚜鍔ㄧ敓鎴恥uid锛屽洜涓哄墠绔病鏈夋満浼氳姹傞獙璇佺爜鑾峰緱uuid
+        // 2023-07-03, 娣诲姞绗笁鏂瑰鎺ョ殑楠岃瘉绫诲瀷锛屼篃闇�瑕佽嚜鍔ㄧ敓鎴怳UID锛屽洜涓哄墠绔洿鎺ヨ姹傚悗鍙帮紙鐩墠棰勭畻涓�浣撳寲浣跨敤锛�
+        CaptchaType currentCaptchaType = loginCallback.getCaptchaProvider().getCaptchaType();
+        if(currentCaptchaType == CaptchaType.None
+                || currentCaptchaType == CaptchaType.ThirdParty){
+            requestLogin.setUuid(IdUtils.simpleUUID());
+        }
+
+        // 娣诲姞token澶辨晥鏃堕棿锛堜粠閰嶇疆鑾峰彇锛夛紝2023-03-28
+        long expiredMinutes = SecurityConfigUtils.getTokenExpireMinutes(requestLogin.getClientType(), this.getSecurityProperties());
+        String token = TokenUtils.generateToken(userDetails.getUserPrincipal().getId()
+                , userDetails.getUsername(), requestLogin.getUuid(), this.getTokenGenerator(), expiredMinutes);
+        logger.debug("token澶辨晥鍒嗛挓:{}", expiredMinutes);
+//        String token = this.tokenGenerator.createToken(requestLogin.getUuid(), userDetails.getUserPrincipal().getId()
+//                , VariableConstants.DEFAULT_TOKEN_EXPIRED_MINUTES, VariableConstants.TOKEN_SECRET);
+        // 缂撳瓨鐧诲綍淇℃伅
+        // 2024-01-05 鐧诲綍缂撳瓨锛屽け鏁堟椂闂村簲褰撻暱涓�浜涳紝绯荤粺榛樿30澶┿�傝繖鍜宼oken
+        long loginCacheExpiredTime = VariableConstants.DEFAULT_TOKEN_EXPIRED_MINUTES;
+        if(expiredMinutes > loginCacheExpiredTime){
+            loginCacheExpiredTime = expiredMinutes;
+        }
+        this.getUserOnlineProvider().cacheUserPrincipal(requestLogin.getUuid(), userDetails.getUserPrincipal(), loginCacheExpiredTime);
+        // 鎶婃垚鍔熺櫥褰曟棩蹇楋紝涓巙uid鍏宠仈淇濆瓨鏀句竴璧凤紝鍦ㄥ紓姝ヤ腑璋冪敤銆�2023-03-23
+        this.recordLoginInfo(username, String.valueOf(ResponseCode.SUCCESS.getCode()), "鐧诲綍鎴愬姛"
+                , userDetails.getUserPrincipal().getUserInfo().getId(), requestLogin.getUuid(), requestLogin.getClientType());
+
+        // 2023-08-18锛岀櫥褰曟垚鍔熷洖璋�
+        AfterLoginCallback afterLoginCallback = PlatformCallbackPostProcessor.getCallbackObject(AfterLoginCallback.class);
+        if(afterLoginCallback != null){
+            afterLoginCallback.onSuccess(requestLogin, userDetails.getUserPrincipal());
+        }
+
+        // 2023-05-12锛屽姞涓婄敤鎴蜂俊鎭紙鍟嗘埛绯荤粺鐢級
+        Map<String, Object> param = new HashMap<>(2);
+        param.put(com.walker.web.Constants.TOKEN_NAME, token);
+        param.put(SecurityConstants.KEY_USER_INFO, UserUtils.acquireClientUserInfo(userDetails.getUserPrincipal().getUserInfo(), token));
+        param.put(SecurityConstants.KEY_USER_INFO_APP, userDetails.getUserPrincipal());
+//        return ResponseValue.success(ResponseValueUtils.acquireOneParam(com.walker.web.Constants.TOKEN_NAME, token));
+        return param;
+    }
+
+    private String validateCaptcha(String code, String uuid, CaptchaProvider<CaptchaResult> captchaProvider){
+        if(StringUtils.isEmpty(uuid) || StringUtils.isEmpty(code)){
+//            throw new CaptchaException();
+            return "璇疯緭鍏ラ獙璇佺爜";
+        }
+
+        CaptchaResult captchaResult = new CaptchaResult();
+        captchaResult.setUuid(uuid);
+        captchaResult.setCode(code);
+        boolean success = captchaProvider.validateCaptcha(captchaResult);
+
+        // 2023-04-07 璋冩暣锛屼娇鐢ㄦ彁渚涜�呭垽鏂獙璇佺爜鏄惁姝g‘銆�
+        // 2023-06-30 鍙湁鐭俊楠岃瘉鐮佹椂锛屼笉鑳藉垹闄ょ紦瀛樼殑楠岃瘉鐮侊紝鍥犱负瀛樺湪鎵嬫満绔櫥褰曪紙骞跺悓鏃舵敞鍐岋級鎯呭喌锛屼細璋冪敤涓ゆlogin鎿嶄綔銆�
+        if(captchaProvider.getCaptchaType() != CaptchaType.SmsCode){
+            this.getCaptchaCacheProvider().removeCacheData(com.iplatform.base.Constants.CAPTCHA_CODE_PREFIX + uuid);// 鍒犻櫎缂撳瓨鐨勯獙璇佺爜
+        }
+
+        if(!success){
+            logger.error("楠岃瘉鐮佹牎楠屽け璐�: code = " + code);
+            return "楠岃瘉鐮侀敊璇�";
+        }
+
+        /*String verifyKey = Constants.CAPTCHA_CODE_PREFIX + uuid;
+        String captchaCode = this.captchaCacheProvider.getCacheData(verifyKey);
+        if(StringUtils.isEmpty(captchaCode)){
+            return "楠岃瘉鐮佷笉瀛樺湪锛屽彲鑳藉凡缁忓け鏁�";
+        }
+        this.captchaCacheProvider.removeCacheData(verifyKey);   // 鍒犻櫎缂撳瓨鐨勯獙璇佺爜
+        if(!code.equalsIgnoreCase(captchaCode)){
+            logger.error("楠岃瘉鐮佹牎楠屽け璐�:" + captchaCode + ", code = " + code);
+            return "楠岃瘉鐮侀敊璇�";
+        }*/
+        return null;
+    }
+
+    private void recordLoginInfo(String loginId, String status, String message, long userId, String uuid, String clientType){
+        if(this.getLogProperties().isLoginEnabled()){
+            logger.debug("寮傛璁板綍鐧诲綍鏃ュ織锛屽悗缁琛ュ厖:" + status + ", " + message);
+            AsyncManager.me().execute(this.acquireLoginInfoTask(loginId, status, message, userId, uuid, clientType));
+        }
+    }
+
+    private TimerTask acquireLoginInfoTask(String loginId, String status, String message, Long userId
+            , String uuid, String clientType){
+        HttpServletRequest request = ServletUtils.getRequest();
+        final WebUserAgent webUserAgent = this.getWebAgentService().getWebUserAgent(request.getHeader("User-Agent"), request);
+
+        return new TimerTask() {
+            @Override
+            public void run() {
+                S_login_info login_info = new S_login_info();
+                login_info.setLogin_time(Long.parseLong(DateUtils.getDateTimeSecondForShow()));
+                login_info.setUser_name(loginId);
+                login_info.setMsg(message);
+                login_info.setStatus(status);
+                login_info.setInfo_id(NumberGenerator.getLongSequenceNumber());
+                if(webUserAgent != null){
+                    login_info.setLogin_location(webUserAgent.getLocation());
+                    login_info.setBrowser(webUserAgent.getBrowserName());
+                    login_info.setIpaddr(webUserAgent.getIp());
+                    login_info.setOs(webUserAgent.getOsName());
+                }
+
+                // 2023-03-23
+                if(status.equals(String.valueOf(ResponseCode.SUCCESS.getCode()))){
+                    S_user_login user_login = null;
+                    if(getLoginStrategyManager().hasUserLogin(loginId)){
+                        user_login = getLoginService().execUpdateUserLogin(userId, loginId, uuid, clientType, login_info, true);
+                        getLoginStrategyManager().updateUserLoginCache(user_login);
+                    } else {
+                        // 鐧诲綍鎴愬姛鎵嶈褰晆uid鍏宠仈缂撳瓨
+                        user_login = getLoginService().execUpdateUserLogin(userId, loginId, uuid, clientType, login_info, false);
+                        getLoginStrategyManager().putUserLoginCache(user_login);
+                    }
+                } else {
+                    // 鐧诲綍澶辫触锛屼粎璁板綍鐧诲綍鏃ュ織
+                    getLogService().execInsertLoginLog(login_info, userId);
+                }
+            }
+        };
+    }
+
+    private AuthenticationManager getAuthenticationManager(){
+        return BeanContextAware.getBeanByType(AuthenticationManager.class);
+    }
+    private TokenGenerator getTokenGenerator(){
+        return BeanContextAware.getBeanByType(TokenGenerator.class);
+    }
+    private CacheProvider<String> getCaptchaCacheProvider(){
+        return (CacheProvider<String>)BeanContextAware.getBeanByName(BEAN_NAME_CAPTCHA_CACHE);
+    }
+    private WebAgentService getWebAgentService(){
+        return BeanContextAware.getBeanByType(WebAgentService.class);
+    }
+    private UserOnlineProvider getUserOnlineProvider(){
+        return BeanContextAware.getBeanByType(UserOnlineProvider.class);
+    }
+    private SecurityProperties getSecurityProperties(){
+        return BeanContextAware.getBeanByType(SecurityProperties.class);
+    }
+    private LogProperties getLogProperties(){
+        return BeanContextAware.getBeanByType(LogProperties.class);
+    }
+    private LoginServiceImpl getLoginService(){
+        return BeanContextAware.getBeanByType(LoginServiceImpl.class);
+    }
+    private LogServiceImpl getLogService(){
+        return BeanContextAware.getBeanByType(LogServiceImpl.class);
+    }
+    private LoginStrategyManager getLoginStrategyManager(){
+        return BeanContextAware.getBeanByType(LoginStrategyManager.class);
+    }
+
+    private static final String BEAN_NAME_CAPTCHA_CACHE = "captchaCacheProvider";
+    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`
+    //~ 浠ヤ笂鏄櫥褰曟柟娉曟娊鍙栦唬鐮併��2023-06-28
+    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`
+
+    @Deprecated
+    public void loginAsWorkflowRole(){
+        DefaultUserDetails userDetails = this.getCurrentUserDetails();
+        userDetails.addGrantedAuthority(Constants.ROLE_ACTIVITI_USER);
+        logger.debug("......loginAsWorkflowRole(), {}", userDetails.getRoleIdList());
+    }
+
+    @Override
+    public List<String> getCurrentUserRoleIdList(){
+        DefaultUserDetails userDetails = this.getCurrentUserDetails();
+        if(userDetails == null){
+            logger.error("鑾峰彇褰撳墠鐧诲綍鐢ㄦ埛閿欒锛歡etCurrentUserDetails() == null");
+            return null;
+        }
+        return userDetails.getRoleIdList();
+    }
+
+    @Override
+    public UserPrincipal<S_user_core> getCurrentUserPrincipal() {
+        DefaultUserDetails userDetails = this.getCurrentUserDetails();
+        if(userDetails == null){
+            logger.error("鑾峰彇褰撳墠鐧诲綍鐢ㄦ埛閿欒锛歡etCurrentUserDetails() == null");
+            return null;
+        }
+        return userDetails.getUserPrincipal();
+    }
+
+    @Override
+    public S_user_core getCurrentUser() {
+        UserPrincipal<S_user_core> userPrincipal = this.getCurrentUserPrincipal();
+        if(userPrincipal == null){
+            throw new WebRuntimeException("褰撳墠鎿嶄綔鏈壘鍒扮櫥褰曚汉鍛�: userPrincipal not found in thread!");
+        }
+        return userPrincipal.getUserInfo();
+    }
+
+    @Override
+    public long getCurrentUserId() {
+        S_user_core user = this.getCurrentUser();
+        return user.getId();
+    }
+
+    @Override
+    public String encryptPassword(String password) {
+        PasswordEncoder passwordEncoder = BeanContextAware.getBeanByType(PasswordEncoder.class);
+        return passwordEncoder.encode(password);
+    }
+
+    @Override
+    public boolean matchesPassword(String rawPassword, String encodedPassword) {
+        PasswordEncoder passwordEncoder = BeanContextAware.getBeanByType(PasswordEncoder.class);
+        return passwordEncoder.matches(rawPassword, encodedPassword);
+    }
+
+    private DefaultUserDetails getCurrentUserDetails(){
+        Authentication authentication = this.getAuthentication();
+        if(authentication == null){
+            throw new WebRuntimeException("褰撳墠鎿嶄綔鏈壘鍒扮櫥褰曡璇佸璞�: authentication not found in thread!");
+        }
+        Object userDetails = authentication.getPrincipal();
+        if(userDetails instanceof DefaultUserDetails){
+            return (DefaultUserDetails) userDetails;
+        }
+        return null;
+    }
+
+    /**
+     * 鑾峰彇Authentication
+     * @author 鏃跺厠鑻�
+     * @date 2022-11-10
+     */
+    private Authentication getAuthentication() {
+        return SecurityContextHolder.getContext().getAuthentication();
+    }
+
+    /**
+     * 杩斿洖绯荤粺閰嶇疆鍙彉鍙傛暟瀵硅薄銆�
+     * @param key 鍙傛暟 key
+     * @return
+     * @date 2022-11-29
+     */
+    private Variable getArgumentVariable(String key){
+        Variable v =  BeanContextAware.getBeanByType(ArgumentsManager.class).getVariable(key);
+        if(v == null){
+            throw new IllegalArgumentException("鍙彉閰嶇疆鍙傛暟涓嶅瓨鍦�: " + key);
+        }
+        return v;
+    }
+}
diff --git a/iplatform-base-security-consum/src/main/java/com/iplatform/security/DefaultUserDetails.java b/iplatform-base-security-consum/src/main/java/com/iplatform/security/DefaultUserDetails.java
new file mode 100644
index 0000000..94ae1c0
--- /dev/null
+++ b/iplatform-base-security-consum/src/main/java/com/iplatform/security/DefaultUserDetails.java
@@ -0,0 +1,171 @@
+package com.iplatform.security;
+
+import com.iplatform.model.po.S_user_core;
+import com.walker.infrastructure.utils.StringUtils;
+import com.walker.web.UserPrincipal;
+import com.walker.web.UserType;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Spring Security 瀹氫箟鐨勭敤鎴风粏鑺傚璞★紝鍦ㄨ璇佷互鍙婅繃婊ゆ潈闄愭椂浣跨敤銆�
+ * @author 鏃跺厠鑻�
+ * @date 2022-10-31
+ */
+public class DefaultUserDetails implements UserDetails {
+
+    private List<GrantedAuthority> grantedList = new ArrayList<GrantedAuthority>(4);
+    private List<String> roleIdList = new ArrayList<>(4);   // 鐢ㄦ埛鍖呭惈瑙掕壊ID闆嗗悎锛屽鍔犲啑浣欑湅鍓嶇鏄惁闇�瑕�
+
+    private UserPrincipal<S_user_core> userPrincipal = null;
+
+    public DefaultUserDetails(UserPrincipal<S_user_core> userPrincipal){
+        if(userPrincipal == null){
+            throw new IllegalArgumentException("UserPrincipal is required!");
+        }
+        this.userPrincipal = userPrincipal;
+    }
+
+    public UserPrincipal<S_user_core> getUserPrincipal(){
+        return this.userPrincipal;
+    }
+
+    @Override
+    public Collection<? extends GrantedAuthority> getAuthorities() {
+        return this.grantedList;
+    }
+
+    @Override
+    public String getPassword() {
+        return this.userPrincipal.getPassword();
+    }
+
+    @Override
+    public String getUsername() {
+        return this.userPrincipal.getUserName();
+    }
+
+    @Override
+    public boolean isAccountNonExpired() {
+        return true;
+    }
+
+    @Override
+    public boolean isAccountNonLocked() {
+        return !this.userPrincipal.isAccountLocked();
+    }
+
+    @Override
+    public boolean isCredentialsNonExpired() {
+        return true;
+    }
+
+    @Override
+    public boolean isEnabled() {
+        return this.userPrincipal.isEnabled();
+    }
+
+    /**
+     * 杩斿洖鐢ㄦ埛鍖呭惈鐨勮鑹睮D闆嗗悎銆�
+     * @return
+     * @date 2022-11-11
+     */
+    public List<String> getRoleIdList(){
+        return this.roleIdList;
+    }
+
+    /**
+     * 鎶婅鑹睮D闆嗗悎涔熷瓨鍏rincipal锛屽洜涓鸿瀵硅薄浼氭斁鍏ョ紦瀛橈紝鑰� UserDetails 涓嶄細銆�
+     * @date 2022-11-11
+     */
+    public void setRoleIdListToPrincipal(){
+        this.userPrincipal.setRoleIdList(this.roleIdList);
+    }
+
+    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+    //~ 閬楃暀浠g爜锛岀湅鏄惁鑳界敤涓娿��2022-10-31
+    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    public boolean isSupervisor(){
+        return this.userPrincipal.getUserInfo().getUser_type() == UserType.TYPE_SUPER;
+    }
+
+    private static final Map<String, GrantedAuthority> gas = new HashMap<String, GrantedAuthority>(3);
+
+    public void addGrantedAuthority(String roleName){
+//		if(roleName != null
+//				&& (roleName.equals(ROLE_SUPER_ADMIN) || roleName.equals(ROLE_ADMIN)
+//						|| roleName.equals(ROLE_USER))){
+//			this.grantedList.add(gas.get(roleName));
+//		}
+        if(StringUtils.isNotEmpty(roleName)){
+            GrantedAuthority ga = gas.get(roleName);
+            if(ga == null){
+                ga = new SimpleGrantedAuthority(roleName);
+                gas.put(roleName, ga);
+            }
+            this.grantedList.add(ga);
+
+            //
+            if(!this.roleIdList.contains(roleName)){
+                this.roleIdList.add(roleName);
+            }
+        }
+    }
+
+    public boolean equals(Object o){
+        if(o == null) return false;
+        if(o == this) return true;
+        if(o instanceof DefaultUserDetails){
+            DefaultUserDetails _o = (DefaultUserDetails)o;
+            if(_o.getUsername().equals(this.getUsername())
+                    && _o.getPassword().equals(this.getPassword())
+                    && _o.isEnabled() == this.isEnabled()){
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public int hashCode(){
+        int result = 31;
+        return result + 31*this.getUsername().hashCode()
+                + this.getPassword().hashCode() + 31*(this.isEnabled() ? 1 : 0);
+    }
+
+    private String ip;
+
+    public String getIp() {
+        return ip;
+    }
+
+    public void setIp(String ip) {
+        this.ip = ip;
+    }
+
+//    private UserDiagram uerDiagram;
+//
+//    /**
+//     * 杩斿洖鐢ㄦ埛鍏锋湁鐨勮彍鍗曟潈闄愬浘淇℃伅銆�
+//     * @return
+//     */
+//    public UserDiagram getUerDiagram() {
+//        return uerDiagram;
+//    }
+//
+//    public void setUerDiagram(UserDiagram uerDiagram) {
+//        this.uerDiagram = uerDiagram;
+//    }
+
+    @Override
+    public String toString(){
+        return new StringBuilder().append("[userDetails, name=").append(this.getUsername()).append("]").toString();
+    }
+}
diff --git a/iplatform-base-security-consum/src/main/java/com/iplatform/security/DefaultUserDetailsService.java b/iplatform-base-security-consum/src/main/java/com/iplatform/security/DefaultUserDetailsService.java
new file mode 100644
index 0000000..f9ba7f3
--- /dev/null
+++ b/iplatform-base-security-consum/src/main/java/com/iplatform/security/DefaultUserDetailsService.java
@@ -0,0 +1,209 @@
+package com.iplatform.security;
+
+import com.iplatform.base.Constants;
+import com.iplatform.base.DefaultUserPrincipal;
+import com.iplatform.base.SecurityConstants;
+import com.iplatform.base.cache.MenuCacheProvider;
+import com.iplatform.base.service.UserServiceImpl;
+import com.iplatform.base.util.UserUtils;
+import com.iplatform.model.po.S_menu;
+import com.iplatform.model.po.S_user_core;
+import com.iplatform.security.config.SecurityProperties;
+import com.walker.infrastructure.utils.PhoneNumberUtils;
+import com.walker.infrastructure.utils.StringUtils;
+import com.walker.web.UserType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class DefaultUserDetailsService implements UserDetailsService {
+
+    protected final transient Logger logger = LoggerFactory.getLogger(getClass());
+
+    private UserServiceImpl userService = null;
+    private SecurityProperties securityProperties;
+    private MenuCacheProvider menuCacheProvider;
+
+    public void setMenuCacheProvider(MenuCacheProvider menuCacheProvider) {
+        this.menuCacheProvider = menuCacheProvider;
+    }
+
+    public void setSecurityProperties(SecurityProperties securityProperties) {
+        this.securityProperties = securityProperties;
+    }
+
+//    public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
+//        this.passwordEncoder = passwordEncoder;
+//    }
+
+    public void setUserService(UserServiceImpl userService) {
+        this.userService = userService;
+    }
+
+    @Override
+    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
+//        UserPrincipal<S_user_core> userPrincipal = this.acquireUserPrincipal(username);
+        logger.debug("loadUserByUsername = " + username);
+        DefaultUserDetails userDetails = this.acquireUserPrincipal(username);
+        if(userDetails == null) {
+            throw new UsernameNotFoundException("not found user: " + username);
+        }
+        // 琚鐢ㄧ殑鐢ㄦ埛涔熶笉鑳界櫥褰�
+        if(!userDetails.isEnabled()) {
+            throw new UsernameNotFoundException("user is forbidden: " + username);
+        }
+
+        // 楠岃瘉鐢ㄦ埛
+        // 2023-01-28 楠岃瘉瀵嗙爜鏀惧湪鐧诲綍鍥炶皟涓��
+//        this.validateUserInfo(userDetails.getUserPrincipal());
+        return userDetails;
+    }
+
+    /*private void validateUserInfo(UserPrincipal<S_user_core> userPrincipal){
+        // 2023-01-26 閫氳繃 PlatformLoginCallback 鏉ユ牎楠屽瘑鐮併��
+        PlatformLoginCallback loginCallback = LoginCallbackUtils.getLoginCallbackBean(UserType.getType(userPrincipal.getUserInfo().getUser_type()));
+        if(loginCallback == null){
+            throw new ApplicationRuntimeException("鏈壘鍒�: loginCallback, userType = " + userPrincipal.getUserInfo().getUser_type());
+        }
+        boolean success = loginCallback.validatePassword(userPrincipal);
+        if(!success){
+            throw new BadCredentialsException(ResponseCode.USER_CREDENTIALS_ERROR.getMessage());
+        }
+//        Authentication usernamePasswordAuthenticationToken = SecurityContextHolder.getContext().getAuthentication();
+//        String password = usernamePasswordAuthenticationToken.getCredentials().toString();
+//        if(!this.passwordEncoder.matches(password, userPrincipal.getPassword())){
+//            throw new BadCredentialsException(ResponseCode.USER_CREDENTIALS_ERROR.getMessage());
+//        }
+        logger.debug("娓呯┖蹇呰鐨勭紦瀛�:鎴栨洿鏂扮櫥褰曠紦瀛�");
+    }*/
+
+    public DefaultUserDetails acquireUserPrincipal(String loginId){
+        if(StringUtils.isEmpty(loginId)){
+            return null;
+        }
+
+        DefaultUserPrincipal userPrincipal = null;
+
+        // 濡傛灉瓒呯骇绠$悊鍛橈紝涓嶈兘鏌ユ暟鎹簱锛岀洿鎺ュ垱寤哄璞°��2022-11-06
+        if(loginId.equals(Constants.SUPERVISOR_NAME_DEFAULT)){
+            userPrincipal = (DefaultUserPrincipal) UserUtils.createSupervisor(this.securityProperties.getSupervisorPassword());
+            DefaultUserDetails userDetails = new DefaultUserDetails(userPrincipal);
+            // 2022-12-02
+            userDetails.addGrantedAuthority(SecurityConstants.ROLE_SUPER_ADMIN);
+            userDetails.addGrantedAuthority(SecurityConstants.ROLE_ADMIN);
+            userDetails.addGrantedAuthority(SecurityConstants.ROLE_USER);
+//            userDetails.addGrantedAuthority(com.walker.web.Constants.ROLE_ACTIVITI_USER);
+            userDetails.setRoleIdListToPrincipal();
+            return userDetails;
+        }
+
+        // 2023-06-28 鏍规嵁鐧诲綍璐﹀彿鏄惁鎵嬫満鍙凤紝鏀寔绉诲姩绔拰PC绔墜鏈虹櫥褰曟柟寮忋��
+        boolean isPhoneNumber = PhoneNumberUtils.isCellPhoneNumber(loginId);
+        Object[] userInfo = null;
+        if(isPhoneNumber && !this.securityProperties.isUserNameIsPhone()){
+            // 閫氳繃鎵嬫満鍙峰瓧娈垫煡璇㈢敤鎴�
+            userInfo = this.userService.queryLoginUser(loginId, true);
+        } else {
+            // 閫氳繃鐢ㄦ埛鍚嶈嚜鍔ㄦ煡璇㈢敤鎴�
+            userInfo = this.userService.queryLoginUser(loginId, false);
+        }
+
+        if(userInfo == null){
+            logger.debug("鐢ㄦ埛涓嶅瓨鍦�: " + loginId);
+            return null;
+        }
+        S_user_core user = (S_user_core) userInfo[0];       // 鐢ㄦ埛淇℃伅涓�瀹氬瓨鍦�
+        List<String> roleIdList = (List<String>)userInfo[1];// 瑙掕壊ID闆嗗悎锛屼笉涓�瀹氬瓨鍦�
+        logger.debug("鎵惧埌鐢ㄦ埛: " + user.getUser_name());
+
+        // 鍔犲叆鏅�氱敤鎴峰叿鏈夌殑瑙掕壊ID锛屾潈闄愭牴鎹鑹睮D鍒ゆ柇
+        userPrincipal = new DefaultUserPrincipal(user);
+        // 璁剧疆鐧诲綍鏃堕棿锛屽悗闈㈣璁$畻杩囨湡锛�2022-11-14
+        userPrincipal.setLastLoginTime(System.currentTimeMillis());
+        DefaultUserDetails userDetails = new DefaultUserDetails(userPrincipal);
+        if(roleIdList != null){
+            for(String roleId : roleIdList){
+                userDetails.addGrantedAuthority(roleId);
+            }
+        }
+
+        // 2022-12-21锛岀敤鎴锋暟鎹潈闄� =========================
+        // 2023-07-17锛岀敱浜巓racle鏌ヨ鎶ラ敊锛坕n (:roleIds)锛�,鏆傛椂鍏抽棴鏁版嵁鏉冮檺鏌ヨ
+//        Map<String, String> dataScopeMap = this.acquireUserDataScopeList(roleIdList);
+//        if(dataScopeMap != null){
+//            logger.debug("鐢ㄦ埛鏁版嵁鏉冮檺闆嗗悎 = " + dataScopeMap);
+//            userPrincipal.setDataScopeMap(dataScopeMap);
+//        }
+        // ================================================
+
+        // 2022-11-15
+        int userType = userDetails.getUserPrincipal().getUserInfo().getUser_type();
+
+        /* 璁剧疆鐢ㄦ埛鐨勮鑹茬被鍨� */
+        if(userType == UserType.TYPE_SUPER){
+            userDetails.addGrantedAuthority(SecurityConstants.ROLE_SUPER_ADMIN);
+            userDetails.addGrantedAuthority(SecurityConstants.ROLE_ADMIN);
+            userDetails.addGrantedAuthority(SecurityConstants.ROLE_USER);
+
+        } else if(userType == UserType.TYPE_ADMIN || userType == UserType.TYPE_ADMIN_DEPT){
+            userDetails.addGrantedAuthority(SecurityConstants.ROLE_ADMIN);
+            userDetails.addGrantedAuthority(SecurityConstants.ROLE_USER);
+
+//        } else if(userType == UserType.TYPE_NORMAL || userType == UserType.TYPE_APP_REG){
+        } else if(userType == UserType.TYPE_NORMAL){
+            userDetails.addGrantedAuthority(SecurityConstants.ROLE_USER);
+
+        } else if(userType == UserType.TYPE_APP_REG){
+            // 2023-01-27 app娉ㄥ唽鐢ㄦ埛锛屼笉缁欎换浣曡鑹叉潈闄�
+            // 2023-03-20 app娉ㄥ唽鐢ㄦ埛锛岄渶瑕佺粰'ROLE_USER'锛屽洜涓鸿繕闇�瑕佽闂叕鍏辨潈闄愶紙鐧诲綍鍚庨兘鑳界湅鐨勫锛�/permit/**,/getInfo锛夛紝浣嗕笉缁欎换浣曡鑹诧紒
+            userDetails.addGrantedAuthority(SecurityConstants.ROLE_USER);
+
+        } else if(userType == UserType.TYPE_MERCHANT_ADMIN){
+            // 2023-06-06 鍟嗘埛绠$悊鍛橈紙娉涙寚鐙珛涓氬姟鍗曚綅鐨勶細鍗曚綅绠$悊鍛橈級
+            userDetails.addGrantedAuthority(SecurityConstants.ROLE_MERCHANT);
+            userDetails.addGrantedAuthority(SecurityConstants.ROLE_USER);
+
+        } else
+            throw new IllegalArgumentException("unknown user type: " + userType);
+
+        // 娣诲姞宸ヤ綔娴佽鑹诧紝鍚﹀垯activiti7鑰佹姤閿�'鏃犳潈闄�'锛�2023-03-21
+//        userDetails.addGrantedAuthority(com.walker.web.Constants.ROLE_ACTIVITI_USER);
+        //
+        userDetails.setRoleIdListToPrincipal();
+
+        return userDetails;
+    }
+
+    /**
+     * 鐢变簬oracle鏌ヨ鎶ラ敊锛坕n (:roleIds)锛�,鏆傛椂鍏抽棴鏁版嵁鏉冮檺鏌ヨ
+     * @param roleIdList
+     * @return
+     * @date 2023-07-17
+     */
+    @Deprecated
+    private Map<String, String> acquireUserDataScopeList(List<String> roleIdList){
+        if(StringUtils.isEmptyList(roleIdList)){
+            return null;
+        }
+        List<String> dataScopeMenuIdList = this.userService.queryUserDataScopeMenuIdList(roleIdList);
+        if(StringUtils.isEmptyList(dataScopeMenuIdList)){
+            return null;
+        }
+        Map<String, String> dataScopeMap = new HashMap<>(8);
+        S_menu menu = null;
+        for(String menuId : dataScopeMenuIdList){
+            menu = this.menuCacheProvider.getCacheData(menuId);
+            if(menu == null){
+                throw new IllegalStateException("鑿滃崟缂撳瓨涓嶅瓨鍦�:" + menuId);
+            }
+            dataScopeMap.put(menu.getParent_id(), menuId.replaceFirst(Constants.DATA_SCOPE_NAME, StringUtils.EMPTY_STRING));
+        }
+        return dataScopeMap;
+    }
+}
diff --git a/iplatform-base-security-consum/src/main/java/com/iplatform/security/FailedAuthenticationEntryPoint.java b/iplatform-base-security-consum/src/main/java/com/iplatform/security/FailedAuthenticationEntryPoint.java
new file mode 100644
index 0000000..3b627df
--- /dev/null
+++ b/iplatform-base-security-consum/src/main/java/com/iplatform/security/FailedAuthenticationEntryPoint.java
@@ -0,0 +1,36 @@
+package com.iplatform.security;
+
+import com.walker.infrastructure.utils.JsonUtils;
+import com.walker.web.ResponseCode;
+import com.walker.web.ResponseValue;
+import com.walker.web.util.ServletUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.AuthenticationEntryPoint;
+
+import javax.servlet.ServletException;
+import java.io.IOException;
+
+/**
+ * 鍖垮悕鐢ㄦ埛璁块棶鏃犳潈闄愯祫婧愭椂鐨勫紓甯搞��
+ * @author 鏃跺厠鑻�
+ * @date 2022-10-31
+ */
+public class FailedAuthenticationEntryPoint implements AuthenticationEntryPoint {
+
+    protected final transient Logger logger = LoggerFactory.getLogger(getClass());
+
+    @Override
+    public void commence(javax.servlet.http.HttpServletRequest request
+            , javax.servlet.http.HttpServletResponse response
+            , AuthenticationException authException) throws IOException, ServletException {
+
+        String msg = "璁よ瘉澶辫触锛屾棤鏉冮檺璁块棶绯荤粺璧勬簮" + request.getRequestURI();
+        try {
+            ServletUtils.renderString(response, JsonUtils.objectToJsonString(ResponseValue.error(ResponseCode.EXCEPTION.getCode(), msg)));
+        } catch (Exception e) {
+            logger.error("鏃犳潈闄愯闂郴缁熻祫婧�" + request.getRequestURI());
+        }
+    }
+}
diff --git a/iplatform-base-security-consum/src/main/java/com/iplatform/security/JwtAuthenticationTokenFilter.java b/iplatform-base-security-consum/src/main/java/com/iplatform/security/JwtAuthenticationTokenFilter.java
new file mode 100644
index 0000000..241bb83
--- /dev/null
+++ b/iplatform-base-security-consum/src/main/java/com/iplatform/security/JwtAuthenticationTokenFilter.java
@@ -0,0 +1,195 @@
+package com.iplatform.security;
+
+import com.iplatform.base.DefaultUserPrincipal;
+import com.iplatform.base.SecurityConstants;
+import com.iplatform.base.VariableConstants;
+import com.iplatform.base.util.TokenUtils;
+import com.iplatform.core.TokenAwareContext;
+import com.iplatform.core.TokenEntity;
+import com.iplatform.model.po.S_user_core;
+import com.iplatform.security.config.SecurityProperties;
+import com.walker.infrastructure.ApplicationRuntimeException;
+import com.walker.web.Constants;
+import com.walker.web.ResponseCode;
+import com.walker.web.ResponseValue;
+import com.walker.web.TokenException;
+import com.walker.web.TokenGenerator;
+import com.walker.web.UserOnlineProvider;
+import com.walker.web.UserPrincipal;
+import com.walker.web.util.ServletUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.List;
+
+public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
+
+    protected final transient Logger logger = LoggerFactory.getLogger(getClass());
+
+    private TokenGenerator tokenGenerator;
+    private UserOnlineProvider userOnlineProvider;
+    private DefaultUserDetailsService defaultUserDetailsService;
+
+    // 2023-03-28
+    private SecurityProperties securityProperties;
+
+    public void setSecurityProperties(SecurityProperties securityProperties) {
+        this.securityProperties = securityProperties;
+    }
+
+    public void setDefaultUserDetailsService(DefaultUserDetailsService defaultUserDetailsService) {
+        this.defaultUserDetailsService = defaultUserDetailsService;
+    }
+
+    public void setUserOnlineProvider(UserOnlineProvider userOnlineProvider) {
+        this.userOnlineProvider = userOnlineProvider;
+    }
+
+    public void setTokenGenerator(TokenGenerator tokenGenerator) {
+        this.tokenGenerator = tokenGenerator;
+    }
+
+    @Override
+    protected void doFilterInternal(HttpServletRequest request
+            , HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
+
+        String token = TokenUtils.getAuthorizationToken(request);
+        if(token != null){
+            try{
+                String data = tokenGenerator.validateToken(token, VariableConstants.TOKEN_SECRET);
+                logger.debug("token_data = " + data);
+                String[] userIdAndKey = TokenUtils.getUserIdAndKey(data);
+                if(userIdAndKey == null || userIdAndKey.length != 3){
+                    throw new ApplicationRuntimeException("token鎼哄甫鐢ㄦ埛淇℃伅瑙f瀽閿欒:" + data);
+                }
+
+                String uuid = userIdAndKey[2];
+                String loginId = userIdAndKey[1];
+                DefaultUserDetails userDetails = null;
+
+                // 鏍规嵁token鑾峰彇鐢ㄦ埛瀵硅薄
+                DefaultUserPrincipal userPrincipal = this.acquireAuthenticationUser(uuid);
+                if(userPrincipal == null){
+                    // 2022-11-15锛岃繖閲岃鍛婅瘔瀹㈡埛绔埛鏂皌oken
+                    // redis涓紦瀛樼櫥褰曟椂闂村簲灏忎簬token澶辨晥鏃堕棿
+                    userDetails = this.defaultUserDetailsService.acquireUserPrincipal(loginId);
+
+                    // 2023-09-03 褰撳墠绔紶鍏ョ殑 token 鏄棤鏁堢殑鎯呭喌涓嬶紝濡傦細鐢ㄦ埛宸蹭笉瀛樺湪锛岄渶瑕佸垹闄ょ櫥褰曠紦瀛�
+                    if(userDetails == null){
+                        this.userOnlineProvider.removeUserPrincipal(uuid);
+                        this.logger.warn("鐢ㄦ埛宸蹭笉瀛樺湪锛屽垹闄ょ櫥褰曠姸鎬佺紦瀛橈細{}", uuid);
+                        return;
+                    }
+
+                    userPrincipal = (DefaultUserPrincipal)userDetails.getUserPrincipal();
+                    logger.debug("token闇�瑕佸埛鏂�: " + userPrincipal.getUserName());
+                    this.tellClientRefreshToken(response, uuid, userPrincipal);
+                    // 2022-11-15锛屼互涓嬪搷搴斾唬鐮佷笉鍐嶉渶瑕侊紝鍥犱负宸茬粡鍒锋柊token锛岄噸鏂扮紦瀛樼櫥褰曠敤鎴凤紝
+//                    ServletUtils.renderString(response, ResponseValue.error(ResponseCode.RE_LOGIN.getCode(), "token涓嶅瓨鍦ㄦ垨宸茶繃鏈燂紝璇烽噸鏂拌璇�"));
+//                    return;
+                } else {
+                    userDetails = this.acquireUserDetails(userPrincipal);
+                }
+
+                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
+                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
+                SecurityContextHolder.getContext().setAuthentication(authentication);
+
+                // 2023-08-05
+                TokenAwareContext.setCurrentToken(new TokenEntity(uuid, loginId));
+
+            } catch (TokenException ex){
+                if(ex.isExpired()){
+                    ServletUtils.renderString(response, ResponseValue.error(ResponseCode.RE_LOGIN.getCode(), "token宸茶繃鏈燂紝璇烽噸鏂拌幏鍙�"));
+                    return;
+                }
+                System.out.println(ex.getTitle());
+                ServletUtils.renderString(response, ResponseValue.error(ResponseCode.ERROR.getCode(), ex.getTitle()));
+                return;
+
+            } catch (Exception ex){
+                logger.error("鏍规嵁token鑾峰緱鐧诲綍淇℃伅閿欒:" + ex.getMessage(), ex);
+                ServletUtils.renderString(response, ResponseValue.error(ResponseCode.ERROR.getCode(), ex.getMessage()));
+                return;
+            }
+        }
+        // 瑕佸皾璇曪細token涓嶅瓨鍦ㄤ笉鑳借闂�
+//        logger.warn("token涓嶅瓨鍦紝鏃犳硶璁块棶绯荤粺鏇磋兘");
+        filterChain.doFilter(request, response);
+        // 2023-08-05
+        TokenAwareContext.clearCurrentToken();
+    }
+
+    /**
+     * 閫氱煡缁堢鍒锋柊token锛宼oken浼氬啓鍏ュ搷搴斿ご涓�: TokenRefresh 瀛楁銆�
+     * @param response
+     * @param uuid
+     * @param userPrincipal
+     */
+    private void tellClientRefreshToken(HttpServletResponse response, String uuid, DefaultUserPrincipal userPrincipal){
+//        String token = this.tokenGenerator.createToken(uuid, userPrincipal.getId()
+//                , VariableConstants.DEFAULT_TOKEN_EXPIRED_MINUTES, VariableConstants.TOKEN_SECRET);
+        // 鍒锋柊token锛岄�氬父PC绔細鐢ㄥ埌锛岀Щ鍔ㄧ鏃堕棿闀夸娇鐢ㄥ嚑鐜囦綆锛屽洜姝よ繖閲屾壘PC绔厤缃��2023-03-28
+        String token = TokenUtils.generateToken(userPrincipal.getId()
+                , userPrincipal.getUserName(), uuid, this.tokenGenerator, securityProperties.getTokenExpireWeb());
+        // 閲嶆柊璁剧疆鐢ㄦ埛鍒涘缓token鏃堕棿
+        userPrincipal.setLastLoginTime(System.currentTimeMillis());
+        this.userOnlineProvider.cacheUserPrincipal(uuid, userPrincipal, securityProperties.getTokenExpireWeb());
+        response.addHeader(Constants.TOKEN_HEADER_REFRESH, token);
+        if(this.logger.isDebugEnabled()){
+            logger.debug("鍒锋柊token, uuid = " + uuid + ", " + token);
+        }
+    }
+
+    private DefaultUserDetails acquireUserDetails(UserPrincipal<S_user_core> userPrincipal){
+        DefaultUserDetails userDetails = new DefaultUserDetails(userPrincipal);
+//        if(userPrincipal.getUserInfo().isSupervisor()){
+        if(userDetails.isSupervisor()){
+            userDetails.addGrantedAuthority(SecurityConstants.ROLE_SUPER_ADMIN);
+            userDetails.addGrantedAuthority(SecurityConstants.ROLE_ADMIN);
+            userDetails.addGrantedAuthority(SecurityConstants.ROLE_USER);
+        } else {
+            // 褰撳墠鏁版嵁搴撳彧鏈変竴涓櫘閫氳鑹�:2
+//            userDetails.addGrantedAuthority("2");
+            // 鍦ㄧ敤鎴风櫥褰曞悗锛岀紦瀛樼殑灏辨湁瑙掕壊ID闆嗗悎锛岃繖閲屾瘡娆¤闂噸鏂拌缃埌瀵硅薄涓��2022-11-11
+            List<String> roleIdList = userPrincipal.getRoleIdList();
+            logger.info("缂撳瓨涓幏鍙� userPrincipal.getRoleIdList() = " + roleIdList);
+            if(roleIdList != null){
+                for(String roleId : roleIdList){
+                    userDetails.addGrantedAuthority(roleId);
+                }
+            }
+        }
+        return userDetails;
+    }
+
+    /**
+     * 妯℃嫙娴嬭瘯锛屽悗缁慨鏀逛负鏁版嵁搴撴柟寮忋��<p></p>
+     * 浠庣紦瀛樹腑璇诲彇鐢ㄦ埛鐧诲綍淇℃伅锛屽鏋滄崲鎴愬け鏁堜负绌恒��
+     * @param uuid
+     * @return
+     * @date 2022-11-15
+     */
+    private DefaultUserPrincipal acquireAuthenticationUser(String uuid){
+        /*String userId = userIdAndKey[0];
+        if(userId.equals("0")){
+            // 0 涓鸿秴绾х鐞嗗憳
+            return MockPrincipalUtils.createSupervisor();
+        } else {
+            // 鍏朵粬鍊兼ā鎷熶负鏅�氱敤鎴�
+            return MockPrincipalUtils.createNormalUser("100");
+        }*/
+        // uuid
+//        String loginKey = userIdAndKey[2];
+        return (DefaultUserPrincipal)this.userOnlineProvider.getUserPrincipal(uuid);
+    }
+}
diff --git a/iplatform-base-security-consum/src/main/java/com/iplatform/security/callback/EncryptPasswordLoginCallback.java b/iplatform-base-security-consum/src/main/java/com/iplatform/security/callback/EncryptPasswordLoginCallback.java
new file mode 100644
index 0000000..f9cc0f1
--- /dev/null
+++ b/iplatform-base-security-consum/src/main/java/com/iplatform/security/callback/EncryptPasswordLoginCallback.java
@@ -0,0 +1,57 @@
+package com.iplatform.security.callback;
+
+import com.iplatform.base.util.PlatformRSAUtils;
+import com.iplatform.model.po.S_user_core;
+import com.walker.web.CaptchaType;
+import com.walker.web.UserPrincipal;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+
+/**
+ * 绉诲姩绔�氳繃锛氳处鍙枫�佸瘑鐮佹柟寮忕櫥褰曪紝<br>
+ * 涓嶉渶瑕佷换浣曢獙璇佺爜銆�
+ * @author 鏃跺厠鑻�
+ * @date 2023-03-20
+ * @date 2023-04-07 淇敼鍚嶅瓧涓�'瀵嗙爜鍔犲瘑'鐧诲綍鍥炶皟瀹炵幇銆�
+ */
+public class EncryptPasswordLoginCallback extends
+//        GeneralLoginCallback
+        SimplePasswordLoginCallback
+{
+
+//    @Deprecated
+//    @Override
+//    public Object[] queryLoginUser(String loginId) {
+//        return new Object[0];
+//    }
+
+    @Override
+    public boolean validatePassword(UserPrincipal<S_user_core> userPrincipal) {
+        Authentication usernamePasswordAuthenticationToken = SecurityContextHolder.getContext().getAuthentication();
+        String password = usernamePasswordAuthenticationToken.getCredentials().toString();
+        try {
+            // APP浼犺繃鏉ョ殑瀵嗙爜鏄疪SA鍔犲瘑鍐呭銆�
+//            byte[] data = RSAUtil.decryptByPrivateKey(password.getBytes(StandardCharsets.UTF_8), PRIK);
+//            String pass = new String(data);
+            // 2023-06-30 鐩墠鐢靛晢绉诲姩绔櫥褰曪細鎵嬫満鍙� + 瀵嗙爜锛屼娇鐢ㄧ殑鏄槑鏂囧瘑鐮侊紝鍚庣画瑕佹敼鎴愪竴鑷淬��
+            String originPassword = null;
+            if(this.getCaptchaProvider().getCaptchaType() == CaptchaType.None){
+//                originPassword = password;
+                // 2023-08-06 uniapp绔娇鐢ㄥ绉板瘑鐮佺畻娉�
+                originPassword = PlatformRSAUtils.getAesDecryptValue(password);
+            } else {
+                originPassword = PlatformRSAUtils.getRsaDecryptValue(password, PlatformRSAUtils.PRIK);
+            }
+            logger.debug("......... 瑙e瘑鐨刾assword = {}", originPassword);
+            return this.passwordEncoder.matches(originPassword, userPrincipal.getPassword());
+        } catch (Exception e) {
+            logger.error("", e);
+            throw new RuntimeException("瑙f瀽鐧诲綍瀵嗙爜閿欒:" + e.getMessage(), e);
+        }
+    }
+
+//    public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
+//        this.passwordEncoder = passwordEncoder;
+//    }
+//    private PasswordEncoder passwordEncoder = null;
+}
diff --git a/iplatform-base-security-consum/src/main/java/com/iplatform/security/callback/MobilePassCaptchaLoginCallback.java b/iplatform-base-security-consum/src/main/java/com/iplatform/security/callback/MobilePassCaptchaLoginCallback.java
new file mode 100644
index 0000000..2f1da05
--- /dev/null
+++ b/iplatform-base-security-consum/src/main/java/com/iplatform/security/callback/MobilePassCaptchaLoginCallback.java
@@ -0,0 +1,31 @@
+package com.iplatform.security.callback;
+
+import com.iplatform.base.util.PlatformRSAUtils;
+import com.iplatform.model.po.S_user_core;
+import com.walker.web.UserPrincipal;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+
+/**
+ * 绉诲姩绔紙H5锛夛紝浣跨敤锛氱敤鎴峰悕銆佸瘑鐮侊紙AES锛� + 鏅�氶獙璇佺爜鐧诲綍鏂瑰紡銆�
+ * <p>鍥犱负绉诲姩绔笌PC绔瘑鐮佸姞瀵嗘柟寮忎笉涓�鑷达紝鎵�浠ユ棤娉曞鐢≒C鐧诲綍楠岃瘉妯″紡锛屽洜姝ら噸鏂板畾涔夛紒</p>
+ * @author 鏃跺厠鑻�
+ * @date 2023-12-28
+ */
+public class MobilePassCaptchaLoginCallback extends EncryptPasswordLoginCallback{
+
+    @Override
+    public boolean validatePassword(UserPrincipal<S_user_core> userPrincipal) {
+        Authentication usernamePasswordAuthenticationToken = SecurityContextHolder.getContext().getAuthentication();
+        String password = usernamePasswordAuthenticationToken.getCredentials().toString();
+        try {
+            // 绉诲姩绔紝鍙敮鎸丄ES瀵嗙爜鍔犲瘑锛岀洰鍓嶆儏鍐点��2023-12-28
+            String originPassword = PlatformRSAUtils.getAesDecryptValue(password);
+            logger.debug("......... 瑙e瘑鐨刾assword = {}", originPassword);
+            return this.passwordEncoder.matches(originPassword, userPrincipal.getPassword());
+        } catch (Exception e) {
+            logger.error("", e);
+            throw new RuntimeException("瑙f瀽鐧诲綍瀵嗙爜閿欒:" + e.getMessage(), e);
+        }
+    }
+}
diff --git a/iplatform-base-security-consum/src/main/java/com/iplatform/security/callback/NoneCaptchaLoginCallback.java b/iplatform-base-security-consum/src/main/java/com/iplatform/security/callback/NoneCaptchaLoginCallback.java
new file mode 100644
index 0000000..a58e76e
--- /dev/null
+++ b/iplatform-base-security-consum/src/main/java/com/iplatform/security/callback/NoneCaptchaLoginCallback.java
@@ -0,0 +1,11 @@
+package com.iplatform.security.callback;
+
+/**
+ * 涓嶅甫楠岃瘉鐮佺被鍨嬬殑锛堣处鎴枫�佸瘑鐮侊級鐧诲綍鏂瑰紡鎵╁睍銆�
+ * <p>浠呬负浜嗗畾涔変竴绉嶇被鍨嬶紝娌℃湁浠讳綍浠g爜鍙噸鍐�</p>
+ * @author 鏃跺厠鑻�
+ * @date 2023-04-07
+ */
+public class NoneCaptchaLoginCallback extends EncryptPasswordLoginCallback{
+
+}
diff --git a/iplatform-base-security-consum/src/main/java/com/iplatform/security/callback/SimplePasswordLoginCallback.java b/iplatform-base-security-consum/src/main/java/com/iplatform/security/callback/SimplePasswordLoginCallback.java
new file mode 100644
index 0000000..66f86f8
--- /dev/null
+++ b/iplatform-base-security-consum/src/main/java/com/iplatform/security/callback/SimplePasswordLoginCallback.java
@@ -0,0 +1,39 @@
+package com.iplatform.security.callback;
+
+import com.iplatform.base.callback.GeneralLoginCallback;
+import com.iplatform.model.po.S_user_core;
+import com.walker.web.UserPrincipal;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+
+/**
+ * <s>PC绔綉椤电櫥褰曞洖璋冨疄鐜般��</s><p></p>
+ * 鐢ㄦ埛鍚嶅瘑鐮佺櫥褰曟柟寮忓洖璋冨疄鐜般��
+ * @author 鏃跺厠鑻�
+ * @date 2023-01-26
+ * @date 2023-01-28 鐢ㄦ埛鍚嶃�佸瘑鐮佹柟寮忕櫥褰曠殑鍥炶皟瀹炵幇銆�
+ * @date 2023-04-07 閲嶆瀯鍚嶅瓧涓�'鏄庢枃瀵嗙爜'鐧诲綍鍥炶皟瀹炵幇銆傚弬鑰冿細{@linkplain EncryptPasswordLoginCallback}
+ */
+public class SimplePasswordLoginCallback extends GeneralLoginCallback {
+
+    @Deprecated
+    @Override
+    public Object[] queryLoginUser(String loginId) {
+        return this.userService.queryLoginUser(loginId, false);
+    }
+
+    @Override
+    public boolean validatePassword(UserPrincipal<S_user_core> userPrincipal) {
+        Authentication usernamePasswordAuthenticationToken = SecurityContextHolder.getContext().getAuthentication();
+        String password = usernamePasswordAuthenticationToken.getCredentials().toString();
+        logger.debug("鐢ㄦ埛杈撳叆锛�" + password + ", " + userPrincipal.getPassword());
+        return this.passwordEncoder.matches(password, userPrincipal.getPassword());
+    }
+
+    public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
+        this.passwordEncoder = passwordEncoder;
+    }
+
+    protected PasswordEncoder passwordEncoder = null;
+}
diff --git a/iplatform-base-security-consum/src/main/java/com/iplatform/security/callback/SmsCodeLoginCallback.java b/iplatform-base-security-consum/src/main/java/com/iplatform/security/callback/SmsCodeLoginCallback.java
new file mode 100644
index 0000000..246df52
--- /dev/null
+++ b/iplatform-base-security-consum/src/main/java/com/iplatform/security/callback/SmsCodeLoginCallback.java
@@ -0,0 +1,76 @@
+package com.iplatform.security.callback;
+
+import com.iplatform.base.Constants;
+import com.iplatform.base.callback.GeneralLoginCallback;
+import com.iplatform.model.po.S_user_core;
+import com.walker.cache.CacheProvider;
+import com.walker.web.UserPrincipal;
+
+/**
+ * APP鏂瑰紡鐧诲綍鍥炶皟瀹炵幇銆�
+ * @author 鏃跺厠鑻�
+ * @date 2023-01-26
+ * @date 2023-01-28 鐭俊楠岃瘉鐮佺櫥褰曟柟寮忓洖璋�
+ */
+public class SmsCodeLoginCallback extends GeneralLoginCallback {
+
+    /**
+     * 閲嶅啓鏂规硶锛岀煭淇¢獙璇佺爜鐧诲綍锛岄渶瑕侀鍏堥獙璇併�傚惁鍒欏湪绉诲姩绔紙鐗瑰埆鏄敤鎴蜂笉瀛樺湪锛岃繕娌℃敞鍐屾儏鍐典笅锛夌洿鎺ヨ烦杩囧苟璋冪敤鎺ュ彛銆�
+     * @return
+     * @date 2023-06-30
+     */
+    @Override
+    public boolean isValidateCaptcha() {
+         /*APP鐧诲綍鎻愪氦涓嶉渶瑕佷娇鐢ㄩ獙璇佺爜锛屼粎鍦ㄦ帴鏀剁煭淇℃椂浣跨敤
+         鐭俊楠岃瘉鐮佷綔涓哄瘑鐮佷娇鐢紝鎵�浠ユ病鏈夐獙璇佺爜浜�!*/
+        return true;
+    }
+
+    /**
+     * 鏆傛湭浣跨敤鍒拌鏂规硶锛岀湅鍚庣画鎯呭喌銆�
+     * @param loginId
+     * @return
+     */
+    @Deprecated
+    @Override
+    public Object[] queryLoginUser(String loginId) {
+        Object[] userInfo = new Object[2];
+        S_user_core userCore =  this.userService.queryLoginUserOnly(loginId);
+        userInfo[0] = userCore;
+        userInfo[1] = null;
+        return userInfo;
+    }
+
+    /**
+     * 楠岃瘉瀵嗙爜瀹炵幇銆�
+     * @param userPrincipal
+     * @return
+     * @date 2023-06-30 閲嶆柊淇敼锛岀敱浜庣煭淇¢獙璇佺爜浠嶇劧蹇呴』鎻愬墠鏍¢獙锛屾墍浠ョ幇鍦ㄨ繖閲屽氨鏃犻渶浣滀负瀵嗙爜銆�
+     */
+    @Override
+    public boolean validatePassword(UserPrincipal<S_user_core> userPrincipal) {
+//        logger.warn("App鐧诲綍瀵嗙爜楠岃瘉: 鍙兘鏄煭淇℃垨鑰呭瘑鐮侊紝鏍规嵁涓氬姟鎯呭喌瀹炵幇锛岃繖閲�'榛樿楠岃瘉閫氳繃'");
+        /*DefaultAuthenticationToken authenticationToken = (DefaultAuthenticationToken)SecurityContextHolder.getContext().getAuthentication();
+        RequestLogin requestLogin = authenticationToken.getRequestLogin();
+        String smsCode = this.getSmsCode(requestLogin.getUuid());
+        if(StringUtils.isNotEmpty(smsCode) && requestLogin.getPassword().equals(smsCode)){
+            logger.debug("app楠岃瘉瀵嗙爜鎴愬姛锛宻msCode={}, password={}", smsCode, requestLogin.getPassword());
+            return true;
+        }
+        logger.error("app鐧诲綍楠岃瘉鐮侀敊璇紝smsCode = " + smsCode + ", inputPass = " + requestLogin.getPassword());
+        return false;*/
+        return true;
+    }
+
+    private String getSmsCode(String uuid){
+        String verifyKey = Constants.CAPTCHA_CODE_PREFIX + uuid;
+        // 缂撳瓨涓幏鍙栦箣鍓嶇敓鎴愮殑鐭俊楠岃瘉鐮�
+        return this.captchaCacheProvider.getCacheData(verifyKey);
+    }
+
+    public void setCaptchaCacheProvider(CacheProvider<String> captchaCacheProvider) {
+        this.captchaCacheProvider = captchaCacheProvider;
+    }
+
+    private CacheProvider<String> captchaCacheProvider;
+}
diff --git a/iplatform-base-security-consum/src/main/java/com/iplatform/security/callback/ThirdPartyLoginCallback.java b/iplatform-base-security-consum/src/main/java/com/iplatform/security/callback/ThirdPartyLoginCallback.java
new file mode 100644
index 0000000..1645c28
--- /dev/null
+++ b/iplatform-base-security-consum/src/main/java/com/iplatform/security/callback/ThirdPartyLoginCallback.java
@@ -0,0 +1,33 @@
+package com.iplatform.security.callback;
+
+import com.iplatform.model.po.S_user_core;
+import com.walker.web.UserPrincipal;
+
+/**
+ * 绗笁鏂瑰鎺ョ櫥褰曞洖璋冨疄鐜般��
+ * <pre>
+ *     1)璇ュ疄鐜扮洰鍓嶄粎涓洪绠椾竴浣撳寲瀵规帴瀹為獙鐢紝鍏蜂綋闇�瑕佺湅鍚庨潰鏇村鎯呭喌銆�
+ *     2)瀵规帴鏃犻渶楠岃瘉鐮侊紝骞朵笖閲囩敤瀵嗙爜鏄庢枃鏂瑰紡锛屽洜涓洪兘鏄悗鍙版搷浣滐紝涓嶅瓨鍦ㄩ闄┿��
+ * </pre>
+ * @author 鏃跺厠鑻�
+ * @date 2023-07-03
+ */
+public class ThirdPartyLoginCallback extends SimplePasswordLoginCallback{
+
+    @Override
+    public boolean isValidateCaptcha() {
+        // 绗笁鏂瑰鎺ワ紝鏃犻獙璇佺爜銆傛殏鏃朵负棰勭畻涓�浣撳寲瀵规帴浣跨敤銆�
+        return false;
+    }
+
+    /**
+     * 绗笁鏂癸紙鏃犻渶锛夐獙璇佸瘑鐮併��
+     * @param userPrincipal
+     * @return
+     * @date 2023-10-23 鏂版坊鍔犳柟娉曪紝閲嶅啓楠岃瘉瀵嗙爜锛岀敱浜庣涓夋柟浼氱粰鎴戜滑鐢ㄦ埛淇℃伅锛岃繖閲屼竴鑸笉闇�瑕侀獙璇佸瘑鐮併��
+     */
+    @Override
+    public boolean validatePassword(UserPrincipal<S_user_core> userPrincipal) {
+        return true;
+    }
+}
diff --git a/iplatform-base-security-consum/src/main/java/com/iplatform/security/callback/WechatLoginCallback.java b/iplatform-base-security-consum/src/main/java/com/iplatform/security/callback/WechatLoginCallback.java
new file mode 100644
index 0000000..2d72dbe
--- /dev/null
+++ b/iplatform-base-security-consum/src/main/java/com/iplatform/security/callback/WechatLoginCallback.java
@@ -0,0 +1,34 @@
+package com.iplatform.security.callback;
+
+import com.iplatform.model.po.S_user_core;
+import com.walker.web.UserPrincipal;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+
+/**
+ * 寰俊鎺堟潈鐧诲綍锛岀洰鍓嶅叕浼楀彿H5鑷姩鐧诲綍浣跨敤銆�
+ * <pre>
+ *     1)鍓嶇澶勭悊寰俊瀵规帴鑾峰彇accessToken;
+ *     2)璋冪敤鍚庡彴鎺ュ彛鐧诲綍锛屽悗鍙扮粍缁囧弬鏁帮紝瀵嗙爜浠庢暟鎹簱鏌ヨ鍑烘潵锛�
+ *     3)鍥犳瀵嗙爜鐩存帴灏辨槸鍔犲瘑鐨勶紝鐩存帴姣斿灏辫锛堢浉绛夌殑锛�
+ * </pre>
+ * @author 鏃跺厠鑻�
+ * @date 2023-07-27
+ */
+public class WechatLoginCallback extends SimplePasswordLoginCallback{
+
+    @Override
+    public boolean validatePassword(UserPrincipal<S_user_core> userPrincipal) {
+        Authentication usernamePasswordAuthenticationToken = SecurityContextHolder.getContext().getAuthentication();
+        String password = usernamePasswordAuthenticationToken.getCredentials().toString();
+        logger.debug("鐢ㄦ埛杈撳叆锛�" + password + ", " + userPrincipal.getPassword());
+        // 寰俊鐧诲綍锛屼紶杩囨潵鐨勫瘑鐮佸氨鏄暟鎹簱涓煡璇㈢殑锛屽洜涓哄悗鍙颁唬鐮佽皟鐢ㄧ櫥褰曪紒
+        return password.equals(userPrincipal.getPassword());
+    }
+
+    @Override
+    public boolean isValidateCaptcha() {
+        // 鏃犻獙璇佺爜銆�
+        return false;
+    }
+}
diff --git a/iplatform-base-security-consum/src/main/java/com/iplatform/security/config/SecurityProperties.java b/iplatform-base-security-consum/src/main/java/com/iplatform/security/config/SecurityProperties.java
new file mode 100644
index 0000000..c481aa6
--- /dev/null
+++ b/iplatform-base-security-consum/src/main/java/com/iplatform/security/config/SecurityProperties.java
@@ -0,0 +1,172 @@
+package com.iplatform.security.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+import java.util.List;
+
+@ConfigurationProperties(prefix = "iplatform.security")
+public class SecurityProperties {
+
+    private List<String> anonymousList = null;
+
+    private List<String> permitList = null;
+
+    private String supervisorPassword = null;
+
+    private boolean corsEnabled = false;
+
+    private boolean allowPcUserAccessApp = true;
+
+    private long tokenExpireWeb = 120;              // PC绔粯璁�2灏忔椂
+    private long tokenExpireMobile = 60 * 24 * 15;  // 绉诲姩绔粯璁�15澶�
+
+    // 鏀寔鎵嬫満鐧诲綍鏃惰嚜鍔ㄦ敞鍐岋紙鎵嬫満涓嶅瓨鍦ㄥ垯锛岀洿鎺ユ敞鍐岋級
+    private boolean allowMobileLoginReg = false;
+
+    private boolean userNameIsPhone = false;
+
+    /**
+     * 鐢ㄦ埛浣撶郴锛堢敤鎴峰悕锛夐兘鏄墜鏈哄彿銆�
+     * @return
+     * @date 2023-06-28
+     */
+    public boolean isUserNameIsPhone() {
+        return userNameIsPhone;
+    }
+
+    public void setUserNameIsPhone(boolean userNameIsPhone) {
+        this.userNameIsPhone = userNameIsPhone;
+    }
+
+    /**
+     * 鏀寔鎵嬫満鐧诲綍鏃惰嚜鍔ㄦ敞鍐岋紙鎵嬫満涓嶅瓨鍦ㄥ垯锛岀洿鎺ユ敞鍐岋級
+     * @return
+     * @date 2023-06-28
+     */
+    public boolean isAllowMobileLoginReg() {
+        return allowMobileLoginReg;
+    }
+
+    public void setAllowMobileLoginReg(boolean allowMobileLoginReg) {
+        this.allowMobileLoginReg = allowMobileLoginReg;
+    }
+
+    /**
+     * 杩斿洖PC绔痶oken澶辨晥鏃堕棿锛堝垎閽燂級锛岄粯璁わ細120
+     * @return
+     * @date 2023-03-28
+     */
+    public long getTokenExpireWeb() {
+        return tokenExpireWeb;
+    }
+
+    public void setTokenExpireWeb(long tokenExpireWeb) {
+        this.tokenExpireWeb = tokenExpireWeb;
+    }
+
+    /**
+     * 杩斿洖绉诲姩绔痶oken澶辨晥鏃堕棿锛堝垎閽燂級锛岄粯璁わ細60 * 24 * 15 锛�15澶╋級
+     * @return
+     * @date 2023-03-28
+     */
+    public long getTokenExpireMobile() {
+        return tokenExpireMobile;
+    }
+
+    public void setTokenExpireMobile(long tokenExpireMobile) {
+        this.tokenExpireMobile = tokenExpireMobile;
+    }
+
+    public boolean isAllowPcUserAccessApp() {
+        return allowPcUserAccessApp;
+    }
+
+    /**
+     * 璁剧疆鏄惁鍏佽'鍚庡彴PC鐢ㄦ埛'璁块棶鐧诲綍鎵嬫満APP
+     * @param allowPcUserAccessApp
+     * @date 2023-03-20
+     */
+    public void setAllowPcUserAccessApp(boolean allowPcUserAccessApp) {
+        this.allowPcUserAccessApp = allowPcUserAccessApp;
+    }
+
+    /**
+     * 鏄惁鍚敤璺ㄥ煙閰嶇疆锛屽湪 Gateway 妯″紡涓嬶紝鐢变簬缃戝叧宸茬粡閰嶇疆锛岃繖閲屼笟鍔″氨涓嶉渶瑕侀噸澶嶉厤缃簡銆�
+     * @return
+     * @date 2022-12-28
+     */
+    public boolean isCorsEnabled() {
+        return corsEnabled;
+    }
+
+    public void setCorsEnabled(boolean corsEnabled) {
+        this.corsEnabled = corsEnabled;
+    }
+
+    /**
+     * 鑾峰彇瓒呯骇绠$悊鍛樺瘑鐮�(绉樻枃)
+     * @return
+     * @date 2022-12-02
+     */
+    public String getSupervisorPassword() {
+        return supervisorPassword;
+    }
+
+    public void setSupervisorPassword(String supervisorPassword) {
+        this.supervisorPassword = supervisorPassword;
+    }
+
+    /**
+     * 鑾峰緱閰嶇疆鐨勫凡璁よ瘉鐢ㄦ埛閮借兘璁块棶鐨勫湴鍧�闆嗗悎銆�
+     * @return
+     * @date 2022-11-13
+     */
+    public List<String> getPermitList() {
+        return permitList;
+    }
+
+    public void setPermitList(List<String> permitList) {
+        this.permitList = permitList;
+    }
+
+    /**
+     * 鑾峰緱閰嶇疆鐨勫尶鍚嶈闂湴鍧�闆嗗悎
+     * @return
+     */
+    public List<String> getAnonymousList() {
+        return anonymousList;
+    }
+
+    public void setAnonymousList(List<String> anonymousList) {
+        this.anonymousList = anonymousList;
+    }
+
+    /**
+     * 鐢ㄦ埛鍚嶅瘑鐮佹柟寮忕櫥褰曪紝閰嶇疆鐨勯獙璇佺爜鎻愪緵鑰呫��
+     * @return
+     * @date 2023-03-14
+     */
+    public String getLoginCaptchaUserPass() {
+        return loginCaptchaUserPass;
+    }
+
+    public void setLoginCaptchaUserPass(String loginCaptchaUserPass) {
+        this.loginCaptchaUserPass = loginCaptchaUserPass;
+    }
+
+    /**
+     * 鎵嬫満鐭俊鐧诲綍鏂瑰紡锛岄厤缃殑楠岃瘉鐮佹彁渚涜�呫��
+     * @return
+     * @date 2023-03-14
+     */
+    public String getLoginCaptchaSmsCode() {
+        return loginCaptchaSmsCode;
+    }
+
+    public void setLoginCaptchaSmsCode(String loginCaptchaSmsCode) {
+        this.loginCaptchaSmsCode = loginCaptchaSmsCode;
+    }
+
+    private String loginCaptchaUserPass = null;
+    private String loginCaptchaSmsCode = null;
+}
diff --git a/iplatform-base-security-consum/src/main/java/com/iplatform/security/config/WebSecurityConfig.java b/iplatform-base-security-consum/src/main/java/com/iplatform/security/config/WebSecurityConfig.java
new file mode 100644
index 0000000..90761ab
--- /dev/null
+++ b/iplatform-base-security-consum/src/main/java/com/iplatform/security/config/WebSecurityConfig.java
@@ -0,0 +1,492 @@
+package com.iplatform.security.config;
+
+import com.iplatform.base.UserCacheProvider;
+import com.iplatform.base.UserLoginCache;
+import com.iplatform.base.cache.MenuCacheProvider;
+import com.iplatform.base.captcha.JigsawCaptchaProvider;
+import com.iplatform.base.captcha.NoneCaptchaProvider;
+import com.iplatform.base.captcha.ThirdPartyCaptchaProvider;
+import com.iplatform.base.service.UserServiceImpl;
+import com.iplatform.base.util.UserUtils;
+import com.iplatform.core.PlatformConfiguration;
+import com.iplatform.model.po.S_user_core;
+import com.iplatform.security.DefaultAuthenticationFailureHandler;
+import com.iplatform.security.DefaultAuthenticationProvider;
+import com.iplatform.security.DefaultLogoutSuccessHandler;
+import com.iplatform.security.DefaultResourceLoaderProvider;
+import com.iplatform.security.DefaultUserDetailsService;
+import com.iplatform.security.FailedAuthenticationEntryPoint;
+import com.iplatform.security.JwtAuthenticationTokenFilter;
+import com.iplatform.security.callback.EncryptPasswordLoginCallback;
+import com.iplatform.security.callback.MobilePassCaptchaLoginCallback;
+import com.iplatform.security.callback.NoneCaptchaLoginCallback;
+import com.iplatform.security.callback.SmsCodeLoginCallback;
+import com.iplatform.security.callback.ThirdPartyLoginCallback;
+import com.iplatform.security.callback.WechatLoginCallback;
+import com.iplatform.security.event.RoleSecurityUpdateListener;
+import com.iplatform.security.util.SecurityConfigUtils;
+import com.walker.cache.CacheProvider;
+import com.walker.infrastructure.utils.StringUtils;
+import com.walker.web.CaptchaProvider;
+import com.walker.web.CaptchaResult;
+import com.walker.web.TokenGenerator;
+import com.walker.web.UserOnlineProvider;
+import com.walker.web.UserPrincipal;
+import com.walker.web.security.DefaultAccessDecisionManager;
+import com.walker.web.security.DefaultAccessDeniedHandler;
+import com.walker.web.security.DefaultSecurityMetadataSource;
+import com.walker.web.security.ResourceLoadProvider;
+import com.walker.web.token.JwtTokenGenerator;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.Ordered;
+import org.springframework.security.access.AccessDecisionManager;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.web.AuthenticationEntryPoint;
+import org.springframework.security.web.SecurityFilterChain;
+import org.springframework.security.web.access.AccessDeniedHandler;
+import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
+import org.springframework.security.web.authentication.AuthenticationFailureHandler;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
+import org.springframework.security.web.authentication.logout.LogoutFilter;
+import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
+import org.springframework.web.cors.CorsConfiguration;
+import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
+import org.springframework.web.filter.CorsFilter;
+
+import java.util.List;
+
+@Configuration
+public class WebSecurityConfig extends PlatformConfiguration {
+
+    private MenuCacheProvider menuCacheProvider;
+
+    private UserServiceImpl userService;
+
+    private UserOnlineProvider userOnlineProvider;
+    private UserCacheProvider userCacheProvider;
+    private UserLoginCache userLoginCache;
+
+    @Autowired
+    public WebSecurityConfig(MenuCacheProvider menuCacheProvider
+            , UserServiceImpl userService, UserOnlineProvider userOnlineProvider, UserCacheProvider userCacheProvider
+            , UserLoginCache userLoginCache){
+        this.menuCacheProvider = menuCacheProvider;
+        this.userService = userService;
+        this.userOnlineProvider = userOnlineProvider;
+        this.userCacheProvider = userCacheProvider;
+        // 2023-07-11
+        this.userLoginCache = userLoginCache;
+    }
+
+    @Bean
+    public SecurityProperties securityProperties(){
+        return new SecurityProperties();
+    }
+
+    /**
+     * HttpSecurity锛氬拷鐣� antMatchers 涓娇鐢ㄧ殑绔偣鐨勮韩浠介獙璇侊紝鍏朵粬瀹夊叏鍔熻兘灏嗙敓鏁堛��<br></br>
+     * WebSecurity锛氱洿鎺ュ拷鐣ヤ篃涓嶄細杩涜 CSRF xss绛夋敾鍑讳繚鎶ゃ��
+     * @param http
+     * @return
+     * @throws Exception
+     */
+    @Bean
+    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
+
+        DefaultUserDetailsService userDetailsService = userDetailsService(this.securityProperties(), this.userCacheProvider);
+        http.userDetailsService(userDetailsService);
+        // CSRF绂佺敤锛屽洜涓轰笉浣跨敤session
+        http.csrf().disable();
+        // ???
+        http.headers().frameOptions().disable();
+
+        // 鐧诲綍琛屼负鐢辫嚜宸卞疄鐜帮紝鍙傝�� AuthController#login
+        http.formLogin().disable().httpBasic().disable();
+
+        // 鍖垮悕璧勬簮璁块棶鏉冮檺锛岃繑鍥炴棤鏉冮檺鎻愮ず鎺ュ彛
+        http.exceptionHandling().authenticationEntryPoint(failedAuthenticationEntryPoint())
+                // 宸茶璇佺敤鎴锋棤鏉冮檺璁块棶閰嶇疆
+                .accessDeniedHandler(this.accessDeniedHandler())
+                .and()
+                // 鍩轰簬token锛屾墍浠ヤ笉闇�瑕乻ession
+                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
+
+//        http.formLogin().loginProcessingUrl("/login")
+//                        .failureHandler(this.authenticationFailureHandler());
+        // 娉ㄦ剰锛氳繖閲屼笉鑳介厤缃笂闈㈢殑鐧诲綍锛屽惁鍒欏氨涓嶄細鎵ц鑷繁瀹炵幇鐨�/login鏂规硶銆�2022-11-11
+        http.logout().logoutUrl("/logout").logoutSuccessHandler(this.logoutSuccessHandler()).permitAll();
+
+        // 鍖垮悕璁块棶闆嗗悎锛�2022-11-07
+        List<String> anonymousList = this.securityProperties().getAnonymousList();
+        if(!StringUtils.isEmptyList(anonymousList)){
+            http.authorizeHttpRequests().antMatchers(anonymousList.toArray(new String[]{})).permitAll();
+        }
+//        http.authorizeHttpRequests().antMatchers("/login", "/register", "/captchaImage", "/test/**").permitAll();
+//        http.authorizeHttpRequests().antMatchers("/static/**", "/test/**").permitAll();
+//        http.authorizeHttpRequests().antMatchers("/security/**").hasAuthority("query_user");
+
+        // 2023-03-21 娉ㄩ噴鎺夛紝璋冭瘯activiti7鏃跺彂鐜板拰涓嬮潰閲嶅锛�
+        // http.addFilterBefore(securityInterceptor(), FilterSecurityInterceptor.class);
+        /*http.authorizeHttpRequests().withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>(){
+            @Override
+            public <O extends FilterSecurityInterceptor> O postProcess(O object) {
+                object.setAccessDecisionManager(accessDecisionManager());//鍐崇瓥绠$悊鍣�
+                object.setSecurityMetadataSource(securityMetadataSource());//瀹夊叏鍏冩暟鎹簮
+                return object;
+            }
+        });*/
+
+        // 2023-01-28 閰嶇疆鑷畾涔夎璇佹彁渚涜��(瀵嗙爜楠岃瘉鐢�)
+        http.authenticationProvider(this.authenticationProvider(userDetailsService, securityProperties()));
+
+        // 鎵�鏈夎姹傞兘闇�瑕佽璇�
+        http.authorizeHttpRequests().anyRequest().authenticated();
+        // 浣跨敤鑷畾涔夊姩鎬佹嫤鎴櫒锛屾嫤鎴墍鏈夋潈闄愯姹傦紝2022-11-02
+        http.addFilterBefore(securityInterceptor(), FilterSecurityInterceptor.class);
+
+        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+        // token鎷︽埅杩囨护鍣紝2022-11-02
+        // 蹇呴』鍦ㄨ繖閲屾坊鍔犳嫤鎴紝涓嶈兘鏀惧湪'FilterSecurityInterceptor'涔嬪悗锛屽洜涓哄鏋滄斁鍦ㄤ箣鍚庯紝閭d箞灏辨棤娉曡幏寰楃敤鎴蜂俊鎭紝浠庤�屾棤娉�
+        // 鑾峰緱鐢ㄦ埛鎵�鍏锋湁鐨勬潈闄愯鑹查泦鍚�:roleIdList銆�2022-11-14(2)
+        http.addFilterBefore(jwtAuthenticationTokenFilter(userDetailsService), UsernamePasswordAuthenticationFilter.class);
+//        http.addFilterBefore(jwtAuthenticationTokenFilter(), DefaultAuthenticationFilter.class);
+        // 灏濊瘯璁﹋wt鍦║RL鏉冮檺涔嬪悗鎵嶆嫤鎴�, 2022-11-14(1)
+        // 娉ㄦ剰锛氫互涓� UsernamePasswordAuthenticationFilter 闇�瑕佸幓鎺夋墠鑳界敓鏁�
+//        http.addFilterAfter(jwtAuthenticationTokenFilter(), FilterSecurityInterceptor.class);
+        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+        if(this.securityProperties().isCorsEnabled()){
+            // 瑙e喅璺ㄥ煙杩囨护鍣紝2022-11-06
+            http.addFilterBefore(this.corsFilter().getFilter(), JwtAuthenticationTokenFilter.class);
+            // 鏈煡锛�2022-11-11
+            http.addFilterBefore(this.corsFilter().getFilter(), LogoutFilter.class);
+        } else {
+            System.out.println("涓嶆坊鍔犺法鍩熻繃婊ゅ櫒: ");
+        }
+
+        return http.build();
+    }
+
+    /**
+     * 鑾峰彇AuthenticationManager锛堣璇佺鐞嗗櫒锛夛紝鐧诲綍鏃惰璇佷娇鐢�
+     * @param authenticationConfiguration
+     * @return
+     * @throws Exception
+     */
+    @Bean
+    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
+        return authenticationConfiguration.getAuthenticationManager();
+    }
+
+    @Bean
+    public DefaultUserDetailsService userDetailsService(SecurityProperties securityProperties, UserCacheProvider userCacheProvider){
+        DefaultUserDetailsService userDetailsService = new DefaultUserDetailsService();
+        userDetailsService.setUserService(this.userService);
+//        userDetailsService.setPasswordEncoder(passwordEncoder());
+        userDetailsService.setSecurityProperties(securityProperties);
+        userDetailsService.setMenuCacheProvider(this.menuCacheProvider);
+        System.out.println("create UserDetailsService = " + userDetailsService);
+
+        // 2023-05-07锛岃繖閲屾妸瓒呯骇绠$悊鍛樺垵濮嬪寲鍒扮紦瀛�
+        UserPrincipal<S_user_core> userPrincipal = UserUtils.createSupervisor(securityProperties.getSupervisorPassword());
+        userCacheProvider.putUser(userPrincipal.getUserInfo());
+        return userDetailsService;
+    }
+
+    @Bean
+    public PasswordEncoder passwordEncoder(){
+        return new BCryptPasswordEncoder();
+    }
+
+    /**
+     * 鍖垮悕鐢ㄦ埛鏃犳硶璁块棶寮傚父杩斿洖
+     * @return
+     */
+    @Bean
+    public AuthenticationEntryPoint failedAuthenticationEntryPoint(){
+        return new FailedAuthenticationEntryPoint();
+    }
+
+    /**
+     * 宸茶璇佺敤鎴锋嫆缁濊闂祫婧愩��
+     * @return
+     */
+    @Bean
+    public AccessDeniedHandler accessDeniedHandler(){
+        return new DefaultAccessDeniedHandler();
+    }
+
+    @Bean
+    public AuthenticationFailureHandler authenticationFailureHandler(){
+        return new DefaultAuthenticationFailureHandler();
+    }
+
+    @Bean
+    public LogoutSuccessHandler logoutSuccessHandler(){
+        DefaultLogoutSuccessHandler logoutSuccessHandler = new DefaultLogoutSuccessHandler();
+        logoutSuccessHandler.setUserOnlineProvider(this.userOnlineProvider);
+        logoutSuccessHandler.setTokenGenerator(this.tokenGenerator());
+        logoutSuccessHandler.setUserLoginCache(this.userLoginCache);
+        return logoutSuccessHandler;
+    }
+
+    @Bean
+    public AccessDecisionManager accessDecisionManager(){
+        return new DefaultAccessDecisionManager();
+    }
+
+    @Bean
+    public DefaultSecurityMetadataSource securityMetadataSource(ResourceLoadProvider resourceLoadProvider){
+//        DefaultResourceLoaderProvider resourceLoaderProvider = new DefaultResourceLoaderProvider();
+//        resourceLoaderProvider.setMenuCacheProvider(this.menuCacheProvider);
+//        resourceLoaderProvider.setPermitAccessUrls(this.securityProperties().getPermitList());
+//        resourceLoaderProvider.setAnonymousUrlList(this.securityProperties().getAnonymousList());
+//        resourceLoaderProvider.loadResource();
+
+        DefaultSecurityMetadataSource securityMetadataSource = new DefaultSecurityMetadataSource();
+        securityMetadataSource.setResourceLoaderProvider(resourceLoadProvider);
+        return securityMetadataSource;
+    }
+
+    @Bean
+    public FilterSecurityInterceptor securityInterceptor(){
+//        DefaultSecurityInterceptor securityInterceptor = new DefaultSecurityInterceptor();
+        FilterSecurityInterceptor securityInterceptor = new FilterSecurityInterceptor();
+        securityInterceptor.setSecurityMetadataSource(securityMetadataSource(this.resourceLoadProvider()));
+        securityInterceptor.setAccessDecisionManager(accessDecisionManager());
+        logger.info("鍒涘缓锛欶ilterSecurityInterceptor");
+        return securityInterceptor;
+    }
+
+    /**
+     * 瀹氫箟token杩囨护鍣�
+     * @return
+     */
+    @Bean
+    public JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter(DefaultUserDetailsService userDetailsService){
+        JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter = new JwtAuthenticationTokenFilter();
+        jwtAuthenticationTokenFilter.setTokenGenerator(tokenGenerator());
+        jwtAuthenticationTokenFilter.setUserOnlineProvider(this.userOnlineProvider);
+        jwtAuthenticationTokenFilter.setDefaultUserDetailsService(userDetailsService);
+        jwtAuthenticationTokenFilter.setSecurityProperties(this.securityProperties());
+        return jwtAuthenticationTokenFilter;
+    }
+
+    @Bean
+    public TokenGenerator tokenGenerator(){
+        return new JwtTokenGenerator();
+    }
+
+    /**
+     * 寰俊鐧诲綍鍥炶皟瀹炵幇銆�
+     * @param passwordEncoder
+     * @param tokenGenerator
+     * @return
+     * @date 2023-07-27
+     */
+    @Bean
+    public WechatLoginCallback wechatLoginCallback(PasswordEncoder passwordEncoder, TokenGenerator tokenGenerator){
+        WechatLoginCallback callback = new WechatLoginCallback();
+        callback.setTokenGenerator(tokenGenerator);
+        callback.setPasswordEncoder(passwordEncoder);
+        callback.setCaptchaProvider(new NoneCaptchaProvider());
+        return callback;
+    }
+
+    /**
+     * 绗笁鏂圭殑瀵规帴鐧诲綍鍥炶皟瀹炵幇銆傦紙涓洪绠椾竴浣撳寲瀵规帴浣跨敤锛屾洿澶氶渶瑕佹娊璞★級
+     * @param passwordEncoder
+     * @param tokenGenerator
+     * @return
+     * @date 2023-07-03
+     */
+    @Bean
+    public ThirdPartyLoginCallback thirdPartyLoginCallback(PasswordEncoder passwordEncoder, TokenGenerator tokenGenerator){
+        ThirdPartyLoginCallback callback = new ThirdPartyLoginCallback();
+        callback.setTokenGenerator(tokenGenerator);
+        callback.setPasswordEncoder(passwordEncoder);
+        callback.setCaptchaProvider(new ThirdPartyCaptchaProvider());
+        return callback;
+    }
+
+    /**
+     * 绉诲姩绔娇鐢細鐢ㄦ埛鍚嶃�佸瘑鐮侊紙AES锛� + 鏅�氶獙璇佺爜鐧诲綍鏂瑰紡銆�
+     * @param passwordEncoder
+     * @param tokenGenerator
+     * @param securityProperties
+     * @param smsCaptchaProvider
+     * @param imageCaptchaProvider
+     * @param jigsawCaptchaProvider
+     * @return
+     * @date 2023-12-28
+     */
+    @Bean
+    public MobilePassCaptchaLoginCallback mobilePassCaptchaLoginCallback(PasswordEncoder passwordEncoder
+            , TokenGenerator tokenGenerator, SecurityProperties securityProperties
+            , CaptchaProvider<CaptchaResult> smsCaptchaProvider
+            , CaptchaProvider<CaptchaResult> imageCaptchaProvider
+            , JigsawCaptchaProvider jigsawCaptchaProvider){
+        MobilePassCaptchaLoginCallback loginCallback = new MobilePassCaptchaLoginCallback();
+        loginCallback.setTokenGenerator(tokenGenerator);
+        loginCallback.setPasswordEncoder(passwordEncoder);
+        // 閰嶇疆缁勮楠岃瘉鐮佹彁渚涜�咃紝2023-12-28
+        CaptchaProvider<CaptchaResult> captchaProvider = SecurityConfigUtils
+                .findCaptchaProvider(securityProperties.getLoginCaptchaUserPass()
+                        , smsCaptchaProvider, imageCaptchaProvider, jigsawCaptchaProvider);
+        loginCallback.setCaptchaProvider(captchaProvider);
+        return loginCallback;
+    }
+
+    /**
+     * 璐﹀彿銆佸瘑鐮侊紙鍔犲瘑鏂瑰紡锛夌櫥褰曠殑鍥炶皟瀹炵幇锛屼笉鍖呭惈锛氱敤鎴烽獙璇佺爜銆�<p>閫傚悎鍦ㄧЩ鍔ㄧ浣跨敤</p>
+     * @param passwordEncoder
+     * @param tokenGenerator
+     * @return
+     * @date 2023-03-20
+     */
+    @Bean
+    public NoneCaptchaLoginCallback noneCaptchaPasswordLoginCallback(PasswordEncoder passwordEncoder
+            , TokenGenerator tokenGenerator){
+        NoneCaptchaLoginCallback encryptPasswordLoginCallback = new NoneCaptchaLoginCallback();
+        encryptPasswordLoginCallback.setTokenGenerator(tokenGenerator);
+        encryptPasswordLoginCallback.setPasswordEncoder(passwordEncoder);
+        encryptPasswordLoginCallback.setCaptchaProvider(new NoneCaptchaProvider());
+        return encryptPasswordLoginCallback;
+    }
+
+    /**
+     * 鐢ㄦ埛鍚嶃�佸瘑鐮侊紙鏄庢枃锛夌櫥褰曟柟寮忓洖璋冨疄鐜帮紝鍖呭惈锛氶獙璇佺爜缁勪欢锛岄�傚悎PC绔娇鐢ㄣ��
+     * @param tokenGenerator
+     * @param passwordEncoder
+     * @return
+     * @date 2023-01-26
+     */
+    @Bean
+    public EncryptPasswordLoginCallback captchaPasswordLoginCallback(TokenGenerator tokenGenerator
+            , PasswordEncoder passwordEncoder, SecurityProperties securityProperties
+            , CaptchaProvider<CaptchaResult> smsCaptchaProvider
+            , CaptchaProvider<CaptchaResult> imageCaptchaProvider
+            , JigsawCaptchaProvider jigsawCaptchaProvider){
+//        SimplePasswordLoginCallback webLoginCallback = new SimplePasswordLoginCallback();
+        EncryptPasswordLoginCallback webLoginCallback = new EncryptPasswordLoginCallback();
+        webLoginCallback.setTokenGenerator(tokenGenerator);
+        webLoginCallback.setUserOnlineProvider(this.userOnlineProvider);
+        webLoginCallback.setUserService(this.userService);
+        webLoginCallback.setPasswordEncoder(passwordEncoder);
+        // 閰嶇疆缁勮楠岃瘉鐮佹彁渚涜�咃紝2023-03-14
+        CaptchaProvider<CaptchaResult> captchaProvider = SecurityConfigUtils
+                .findCaptchaProvider(securityProperties.getLoginCaptchaUserPass()
+                        , smsCaptchaProvider, imageCaptchaProvider, jigsawCaptchaProvider);
+        webLoginCallback.setCaptchaProvider(captchaProvider);
+        return webLoginCallback;
+    }
+
+    /**
+     * 鐭俊楠岃瘉鐮佺櫥褰曟柟寮忓洖璋冨疄鐜般��
+     * @param tokenGenerator
+     * @param captchaCacheProvider
+     * @return
+     * @date 2023-01-26
+     */
+    @Bean
+    public SmsCodeLoginCallback smsCodeLoginCallback(TokenGenerator tokenGenerator
+            , CacheProvider<String> captchaCacheProvider, SecurityProperties securityProperties
+            , CaptchaProvider<CaptchaResult> smsCaptchaProvider
+            , CaptchaProvider<CaptchaResult> imageCaptchaProvider
+            , JigsawCaptchaProvider jigsawCaptchaProvider){
+        SmsCodeLoginCallback smsCodeLoginCallback = new SmsCodeLoginCallback();
+        smsCodeLoginCallback.setTokenGenerator(tokenGenerator);
+        smsCodeLoginCallback.setUserOnlineProvider(this.userOnlineProvider);
+        smsCodeLoginCallback.setUserService(this.userService);
+        smsCodeLoginCallback.setCaptchaCacheProvider(captchaCacheProvider);
+        // 閰嶇疆缁勮楠岃瘉鐮佹彁渚涜�咃紝2023-03-14
+        CaptchaProvider<CaptchaResult> captchaProvider = SecurityConfigUtils
+                .findCaptchaProvider(securityProperties.getLoginCaptchaSmsCode()
+                        , smsCaptchaProvider, imageCaptchaProvider, jigsawCaptchaProvider);
+        smsCodeLoginCallback.setCaptchaProvider(captchaProvider);
+        return smsCodeLoginCallback;
+    }
+
+    /**
+     * 瑙e喅鍚屾簮璺ㄥ煙闂
+     * @return
+     */
+    @Bean
+    public FilterRegistrationBean<CorsFilter> corsFilter() {
+        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
+        if(!this.securityProperties().isCorsEnabled()){
+            return new FilterRegistrationBean<>(new CorsFilter(source));
+        }
+
+        // 瀵规帴鍙i厤缃法鍩熻缃�
+        source.registerCorsConfiguration("/**", buildConfig());
+        System.out.println("閰嶇疆璺ㄥ煙杩囨护鍣紝this.securityProperties().isCorsEnabled() = true");
+        //鏈夊涓猣ilter鏃舵澶勮缃敼CorsFilter鐨勪紭鍏堟墽琛岄『搴�
+        FilterRegistrationBean<CorsFilter> bean = new FilterRegistrationBean<>(new CorsFilter(source));
+        bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
+        return bean;
+    }
+
+    private CorsConfiguration buildConfig() {
+        CorsConfiguration corsConfiguration = new CorsConfiguration();
+        corsConfiguration.addAllowedOrigin("*");
+        corsConfiguration.addAllowedHeader("*");
+        corsConfiguration.addAllowedMethod("*");
+        corsConfiguration.addExposedHeader("*");
+        return corsConfiguration;
+    }
+
+    /**
+     * 閰嶇疆鑷畾涔夎璇佹彁渚涜�咃紝鑷繁瀹炵幇瀵嗙爜璁よ瘉缁嗚妭锛屽惁鍒檚pring浼氶粯璁ゅ瘑鐮佹瘮杈冿紝瀵艰嚧鎵嬫満鐭俊楠岃瘉鐮佷綔涓哄瘑鐮佹瘮杈冨け鏁堛��
+     * @param userDetailsService
+     * @return
+     * @date 2023-01-28
+     */
+    @Bean
+    public DefaultAuthenticationProvider authenticationProvider(UserDetailsService userDetailsService
+            , SecurityProperties securityProperties){
+        DefaultAuthenticationProvider authenticationProvider = new DefaultAuthenticationProvider();
+        authenticationProvider.setUserDetailsService(userDetailsService);
+        System.out.println("isAllowPcUserAccessApp = " + securityProperties.isAllowPcUserAccessApp());
+        authenticationProvider.setAllowPcUserAccessApp(securityProperties.isAllowPcUserAccessApp());
+        authenticationProvider.setHideUserNotFoundExceptions(false);    // 蹇呴』璁剧疆锛屽惁鍒欎笉浼氭姏鍑鸿寮傚父锛�2023-06-28
+        return authenticationProvider;
+    }
+
+    /**
+     * 鎶婅祫婧愭彁渚涜�呯嫭绔嬪嚭鏉ワ紝鍙互澶嶇敤銆�
+     * @return
+     * @date 2023-05-07
+     */
+    @Bean
+    public ResourceLoadProvider resourceLoadProvider(){
+        DefaultResourceLoaderProvider resourceLoaderProvider = new DefaultResourceLoaderProvider();
+        resourceLoaderProvider.setMenuCacheProvider(this.menuCacheProvider);
+        resourceLoaderProvider.setPermitAccessUrls(this.securityProperties().getPermitList());
+        resourceLoaderProvider.setAnonymousUrlList(this.securityProperties().getAnonymousList());
+        resourceLoaderProvider.loadResource();
+        return resourceLoaderProvider;
+    }
+
+    /**
+     * 瑙掕壊鏉冮檺鍙樻洿鍚庯紝澶勭悊閫氱煡锛屽苟閲嶆柊鍔犺浇璧勬簮淇℃伅銆�
+     * @param resourceLoadProvider
+     * @return
+     * @date 2023-05-07
+     */
+    @Bean
+    public RoleSecurityUpdateListener roleSecurityUpdateListener(ResourceLoadProvider resourceLoadProvider){
+        RoleSecurityUpdateListener listener = new RoleSecurityUpdateListener();
+        listener.setResourceLoaderProvider(resourceLoadProvider);
+        return listener;
+    }
+}
diff --git a/iplatform-base-security-consum/src/main/java/com/iplatform/security/controller/SecurityController.java b/iplatform-base-security-consum/src/main/java/com/iplatform/security/controller/SecurityController.java
new file mode 100644
index 0000000..2645ca5
--- /dev/null
+++ b/iplatform-base-security-consum/src/main/java/com/iplatform/security/controller/SecurityController.java
@@ -0,0 +1,439 @@
+package com.iplatform.security.controller;
+
+import com.iplatform.base.SecuritySpi;
+import com.iplatform.base.SystemController;
+import com.iplatform.base.cache.MenuCacheProvider;
+import com.iplatform.base.callback.SecurityCallback;
+import com.iplatform.base.config.SecurityUserProperties;
+import com.iplatform.base.config.TcpProperties;
+import com.iplatform.base.exception.LoginException;
+import com.iplatform.base.pojo.RequestLogin;
+import com.iplatform.base.service.MenuServiceImpl;
+import com.iplatform.base.util.MenuUtils;
+import com.iplatform.base.util.menu.MenuTree;
+import com.iplatform.base.util.menu.SystemMenu;
+import com.iplatform.model.po.S_user_core;
+import com.iplatform.model.vo.MenuVo;
+import com.iplatform.model.vo.RouterVo;
+import com.walker.infrastructure.utils.JsonUtils;
+import com.walker.infrastructure.utils.StringUtils;
+import com.walker.web.ResponseValue;
+import com.walker.web.UserPrincipal;
+import com.walker.web.UserType;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+@RestController
+public class SecurityController extends SystemController {
+
+//    private CacheProvider<String> captchaCacheProvider;
+//    private AuthenticationManager authenticationManager;
+//    private TokenGenerator tokenGenerator;
+//    private UserOnlineProvider userOnlineProvider;
+    private MenuServiceImpl menuService;
+    private MenuCacheProvider menuCacheProvider;
+//    private WebAgentService webAgentService;
+//    private LogServiceImpl logService;
+//    private LogProperties logProperties;
+//    // 2023-03-22
+//    private LoginServiceImpl loginService;
+//    // 2023-03-28
+//    private SecurityProperties securityProperties;
+    private TcpProperties tcpProperties;
+
+    private SecuritySpi securitySpi;
+    private SecurityUserProperties securityUserProperties;
+
+    @Autowired
+    public SecurityController(
+//            CacheProvider<String> captchaCacheProvider
+//            , AuthenticationManager authenticationManager, TokenGenerator tokenGenerator
+//            , UserOnlineProvider userOnlineProvider
+            MenuServiceImpl menuService, MenuCacheProvider menuCacheProvider
+//            , WebAgentService webAgentService, LogServiceImpl logService, LogProperties logProperties
+//            , LoginServiceImpl loginService
+//            , SecurityProperties securityProperties
+            , TcpProperties tcpProperties, SecuritySpi securitySpi, SecurityUserProperties securityUserProperties){
+//        this.captchaCacheProvider = captchaCacheProvider;
+//        this.authenticationManager = authenticationManager;
+//        this.tokenGenerator = tokenGenerator;
+//        this.userOnlineProvider = userOnlineProvider;
+        this.menuService = menuService;
+        this.menuCacheProvider = menuCacheProvider;
+//        this.webAgentService = webAgentService;
+//        this.logService = logService;
+//        this.logProperties = logProperties;
+//        this.loginService = loginService;
+//        this.securityProperties = securityProperties;
+        this.tcpProperties = tcpProperties;
+        this.securitySpi = securitySpi;
+        this.securityUserProperties = securityUserProperties;
+    }
+
+    @PostMapping("/login")
+//    public ResponseValue login(@RequestBody RequestLogin requestLogin){
+    public ResponseValue login(@RequestBody String raw){
+        logger.debug("login = " + raw);
+        RequestLogin requestLogin = null;
+        try {
+            requestLogin = JsonUtils.jsonStringToObject(raw, RequestLogin.class);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+        String username = requestLogin.getUsername();
+        String password = requestLogin.getPassword();
+
+        if(StringUtils.isEmpty(username) || StringUtils.isEmpty(password)){
+            return ResponseValue.error("璇疯緭鍏ョ敤鎴峰悕鎴栧瘑鐮�");
+        }
+
+        /*// 2023-01-26 涓轰簡鏀寔澶氱鐧诲綍鏂瑰紡锛屼娇鐢ㄧ櫥褰曞洖璋冨鐞嗗叿浣撶櫥褰曠粏鑺傘��
+        PlatformLoginCallback loginCallback = LoginCallbackUtils.getLoginCallbackBean(LoginType.getType(requestLogin.getLoginType()), true);
+
+        boolean captchaEnabled = this.getArgumentVariable(ArgumentsConstants.KEY_SECURITY_CAPTCHA_ENABLED).getBooleanValue();
+        // 2023-01-26 杩欓噷APP绔槸涓嶉渶瑕侀獙璇佺爜鐨�
+        if(captchaEnabled){
+            CaptchaProvider<CaptchaResult> captchaProvider = loginCallback.getCaptchaProvider();
+            if(captchaProvider == null){
+                return ResponseValue.error("绯荤粺闇�瑕侀獙璇佺爜锛屼絾鐧诲綍鏈厤缃�:" + loginCallback.getClass().getName());
+            }
+            if(StringUtils.isEmpty(requestLogin.getVerifyType())){
+                return ResponseValue.error("璇锋眰閿欒锛氶獙璇佺爜绫诲瀷涓虹┖");
+            }
+            if(!requestLogin.getVerifyType().equals(captchaProvider.getCaptchaType().getIndex())){
+                throw new IllegalArgumentException("鍓嶇閰嶇疆鐨勯獙璇佺爜绫诲瀷涓庡悗鍙颁笉涓�鑷�! verifyType = " + captchaProvider.getCaptchaType());
+            }
+            if(loginCallback.isValidateCaptcha()){
+                logger.debug("闇�瑕侀獙璇佺爜锛実etCaptchaType={}", loginCallback.getCaptchaProvider().getCaptchaType());
+                String error = this.validateCaptcha(username, requestLogin.getCode(), requestLogin.getUuid(), captchaProvider);
+                if(error != null){
+                    return ResponseValue.error(error);
+                }
+            }
+        }
+
+        // 鐢ㄦ埛楠岃瘉
+        Authentication authentication = null;
+
+        try{
+//            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
+            DefaultAuthenticationToken authenticationToken = new DefaultAuthenticationToken(username, password, requestLogin);
+            // 杩欓噷鏀惧叆绾跨▼锛屽悗闈serDetailsService浼氫娇鐢�
+            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
+            authentication = authenticationManager.authenticate(authenticationToken);
+
+        } catch (Exception e){
+            this.recordLoginInfo(username, String.valueOf(ResponseCode.ERROR.getCode()), "鐧诲綍鏈垚鍔熻璇�", 0, null, null);
+            if (e instanceof BadCredentialsException){
+                return ResponseValue.error(ResponseCode.USER_CREDENTIALS_ERROR.getCode(), ResponseCode.USER_CREDENTIALS_ERROR.getMessage());
+            } else {
+                if(e instanceof UsernameNotFoundException){
+                    logger.debug(".............鐢ㄦ埛涓嶅瓨鍦細" + username);
+                }
+                // 2023-03-20
+                // 鐧诲綍楠岃瘉鎶涘嚭寮傚父锛屼細鍦ㄨ繖閲岀粺涓�澶勭悊锛屽锛歅cUserStopAppException銆�
+                // DefaultAuthenticationProvider
+                return ResponseValue.error(ResponseCode.USER_CREDENTIALS_ERROR.getCode(), e.getMessage());
+            }
+        }
+
+        DefaultUserDetails userDetails = (DefaultUserDetails)authentication.getPrincipal();
+        if(this.logger.isDebugEnabled()){
+            logger.debug(userDetails.getUserPrincipal().toString());
+        }
+
+        // 2023-03-20锛屽浜庣┖楠岃瘉鐮佺被鍨嬶紙鐧诲綍鏂瑰紡锛夛紝闇�瑕佸悗鍙拌嚜鍔ㄧ敓鎴恥uid锛屽洜涓哄墠绔病鏈夋満浼氳姹傞獙璇佺爜鑾峰緱uuid
+        if(loginCallback.getCaptchaProvider().getCaptchaType() == CaptchaType.None){
+            requestLogin.setUuid(IdUtils.simpleUUID());
+        }
+
+        // 娣诲姞token澶辨晥鏃堕棿锛堜粠閰嶇疆鑾峰彇锛夛紝2023-03-28
+        long expiredMinutes = SecurityConfigUtils.getTokenExpireMinutes(requestLogin.getClientType(), securityProperties);
+        String token = TokenUtils.generateToken(userDetails.getUserPrincipal().getId()
+                , userDetails.getUsername(), requestLogin.getUuid(), this.tokenGenerator, expiredMinutes);
+        logger.debug("token澶辨晥鍒嗛挓:{}", expiredMinutes);
+//        String token = this.tokenGenerator.createToken(requestLogin.getUuid(), userDetails.getUserPrincipal().getId()
+//                , VariableConstants.DEFAULT_TOKEN_EXPIRED_MINUTES, VariableConstants.TOKEN_SECRET);
+        // 缂撳瓨鐧诲綍淇℃伅
+        this.userOnlineProvider.cacheUserPrincipal(requestLogin.getUuid(), userDetails.getUserPrincipal());
+        // 鎶婃垚鍔熺櫥褰曟棩蹇楋紝涓巙uid鍏宠仈淇濆瓨鏀句竴璧凤紝鍦ㄥ紓姝ヤ腑璋冪敤銆�2023-03-23
+        this.recordLoginInfo(username, String.valueOf(ResponseCode.SUCCESS.getCode()), "鐧诲綍鎴愬姛"
+                , userDetails.getUserPrincipal().getUserInfo().getId(), requestLogin.getUuid(), requestLogin.getClientType());
+
+        // 2023-05-12锛屽姞涓婄敤鎴蜂俊鎭紙鍟嗘埛绯荤粺鐢級
+        Map<String, Object> param = new HashMap<>(2);
+        param.put(com.walker.web.Constants.TOKEN_NAME, token);
+        param.put(SecurityConstants.KEY_USER_INFO, UserUtils.acquireClientUserInfo(userDetails.getUserPrincipal().getUserInfo(), token));
+//      */
+        Map<String, Object> param = null;
+        try {
+            param = this.securitySpi.login(requestLogin);
+            return ResponseValue.success(param);
+        } catch (LoginException e) {
+            return ResponseValue.error(e.getMessage());
+        }
+    }
+
+    @RequestMapping("/getInfo")
+    public ResponseValue getUserInfo(){
+        UserPrincipal<S_user_core> userPrincipal = this.getCurrentUserPrincipal();
+        Map<String, Object> data = new HashMap<>(4);
+
+        // 2023-10-13锛屽鍔犳潈闄愯嚜瀹氫箟鍔犺浇鍥炶皟锛屼负涓氬姟棰勭暀閽╁瓙
+        SecurityCallback securityCallback = this.getPlatformCallback(SecurityCallback.class);
+
+        // permissions锛�
+        // 璇ラ泦鍚堢敤浜庨�傞厤鑻ヤ緷鍓嶇锛屽悗缁墠绔皢涓嶉渶瑕佽嚜宸变繚鐣欐潈闄愯矾鐢憋紝缁熶竴鍚庡彴澶勭悊杩斿洖閿欒淇℃伅銆�2022-11-12
+        Set<String> perms = new HashSet<String>();
+        if(userPrincipal.getUserInfo().getUser_type() == UserType.TYPE_SUPER){
+            perms.add("*:*:*");
+        } else {
+            // 鑾峰緱褰撳墠鐢ㄦ埛鎵�灞炵殑瑙掕壊ID闆嗗悎
+            List<String> menuIdList = this.menuService.queryRoleMenuIdList(userPrincipal.getRoleIdList());
+//            perms.addAll(this.menuCacheProvider.getPermissionSet(menuIdList));
+
+            if(securityCallback == null){
+                // 2023-06-01 澧炲姞椤剁骇鍗曚綅鍙娇鐢ㄧ殑鑿滃崟鑼冨洿銆�
+                int menuScope = this.getDeptCacheProvider().getDept(userPrincipal.getUserInfo().getOrg_id()).getMenu_type();
+                if(menuScope == MenuUtils.MENU_SCOPE_PLATFORM){
+                    // 骞冲彴鑿滃崟锛岄渶瑕佹牴鎹鑹叉煡璇�
+                    perms.addAll(this.menuCacheProvider.getPermissionSet(menuIdList, false, menuScope));
+                } else {
+                    // 鍟嗘埛锛堥《绾ф満鏋勶級鐙珛鑿滃崟锛屼笉闇�瑕佽鑹�
+                    perms.addAll(this.menuCacheProvider.getPermissionSet(null, true, menuScope));
+                }
+
+            } else {
+                // 2023-10-13
+                logger.debug("瀛樺湪涓氬姟鑷畾涔夋潈闄愬洖璋冿細{}", securityCallback.getClass().getName());
+                Set<String> userPermission = securityCallback.loadUserPermission(userPrincipal.getUserInfo(), menuIdList);
+                if(userPermission != null){
+                    perms.addAll(userPermission);
+                }
+            }
+        }
+        logger.debug("鐢ㄦ埛 permissions = " + perms);
+
+//        data.put("user", userPrincipal.getUserInfo());
+        data.put("roles", userPrincipal.getRoleIdList());
+        data.put("permissions", perms);
+        data.put("isPerfectInfo", true);    // 鏄惁宸插畬鍠勪俊鎭紝鏆傛椂娌$敤锛屼粎閰嶅悎鍓嶇灞曠ず銆�2023-03-20
+        // 2023-08-05 鏄惁寮哄埗淇敼瀵嗙爜
+        if(this.securityUserProperties.isPassDefaultModify()){
+            data.put("force_change_pass", userPrincipal.getUserInfo().getModify_pwd().intValue() == 1? false : true);
+        } else {
+            data.put("force_change_pass", false);
+        }
+
+        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+        //~ 閫傞厤鐢靛晢妯″潡锛屽鍔犲叾浠栫敤鎴峰睘鎬с��2023-05-12
+        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+        S_user_core user = userPrincipal.getUserInfo();
+        data.put("id", user.getId());
+        data.put("account", user.getUser_name());
+        data.put("realName", user.getNick_name());
+        data.put("roleNames", null);
+        data.put("roleIds", StringUtils.collectionToCommaDelimitedString(userPrincipal.getRoleIdList()));
+//        data.put("Token", null);
+        data.put("phone", user.getPhonenumber());
+        data.put("isSms", true);
+        data.put("merStarLevel", 0);
+
+        // 2023-04-17锛寃ebsocket杩炴帴淇℃伅
+        if(!this.tcpProperties.isEnabled()){
+            logger.warn("鏈紑鍚�'WebSocket'");
+            data.put("uri", "-1");
+        } else {
+            data.put("uri", this.tcpProperties.getWebsocketUri());
+            data.put("uid", userPrincipal.getId());
+        }
+
+        if(securityCallback != null){
+            securityCallback.acquireUserInfo(data, user);
+        }
+        return ResponseValue.success(data);
+    }
+
+    /**
+     * 鑻ヤ緷鍓嶇鏂规硶锛岃幏鍙栬矾鐢辨潈闄愩�傛殏鏃跺簾寮�
+     * @return
+     */
+    @Deprecated
+    @GetMapping("/getRouters")
+    public ResponseValue getRouters(){
+        List<SystemMenu> menuList = this.acquireUserMenuList();
+        List<RouterVo> routerList = this.menuCacheProvider.buildMenus(menuList);
+        return ResponseValue.success(routerList);
+    }
+
+    /**
+     * 鏂扮晫闈㈣繑鍥炶彍鍗曟爲锛岀粍瑁呮暟鎹��
+     * @return
+     * @date 2023-05-12
+     */
+    @GetMapping("/getMenus")
+    public ResponseValue getMenus(){
+        List<SystemMenu> menuList = this.acquireUserMenuList();
+//        logger.debug("acquireUserMenuList = {}", menuList);
+        List<MenuVo> menuVoList = new ArrayList<>(32);
+        if(menuList != null){
+            MenuVo menuVo = null;
+            for(SystemMenu menu: menuList){
+                if(menu.getMenu_type().equals(MenuUtils.MENU_TYPE_BUTTON)){
+                    // 杩欓噷娉ㄦ剰锛岃繖娆″墠绔笉瑕佸姛鑳界偣锛屽彧瑕佽彍鍗曟湰韬��2023-05-13
+                    continue;
+                }
+                menuVo = new MenuVo();
+                menuVo.setId(Long.parseLong(menu.getMenu_id()));
+                menuVo.setPid(Long.parseLong(menu.getParent_id()));
+                menuVo.setName(menu.getMenu_name());
+                menuVo.setPerms(menu.getPerms());
+                menuVo.setComponent(menu.getComponent());
+                menuVo.setSort(menu.getOrder_num());
+                menuVo.setIcon(menu.getIcon());
+                menuVo.setMenuType(menu.getMenu_type());
+//                if(menu.getMenu_type().equals(MenuUtils.MENU_TYPE_FOLDER)){
+//                    menuVo.setMenuType(MenuUtils.MENU_TYPE_FOLDER);
+//                } else if(menu.getMenu_type().equals(MenuUtils.MENU_TYPE_ITEM)){
+//                    menuVo.setMenuType(MenuUtils.MENU_TYPE_ITEM);
+//                } else {
+//                    menuVo.setMenuType(MenuUtils.MENU_TYPE_POINT);
+//                }
+                if(StringUtils.isNotEmpty(menu.getIcon_info())){
+                    String[] customIcons = StringUtils.commaDelimitedListToStringArray(menu.getIcon_info());
+                    if(customIcons.length != 2){
+                        throw new IllegalArgumentException("鑷畾涔夎彍鍗曞浘鏍�(鐩稿璺緞)蹇呴』閰嶇疆涓や釜锛屽苟鐢ㄨ嫳鏂囬�楀彿鍒嗛殧锛宯ame=" + menu.getMenu_name());
+                    }
+                    menuVo.setIconNormal(customIcons[0]);
+                    menuVo.setIconActive(customIcons[1]);
+                }
+                menuVoList.add(menuVo);
+            }
+        }
+//        logger.debug("menuVoList = {}", menuVoList);
+        MenuTree menuTree = new MenuTree(menuVoList);
+        menuVoList = menuTree.buildTree();
+        return ResponseValue.success(menuVoList);
+    }
+
+    private List<SystemMenu> acquireUserMenuList(){
+        List<SystemMenu> menuList = null;
+        UserPrincipal<S_user_core> userPrincipal = this.getCurrentUserPrincipal();
+
+        // 2023-10-13 褰撲笟鍔¢厤缃湁鑷畾涔夎彍鍗曞姞杞藉洖璋冨璞℃椂锛岄渶瑕佹寜鐓т笟鍔¤鍒欏姞杞姐��
+        SecurityCallback securityCallback = this.getPlatformCallback(SecurityCallback.class);
+        if(securityCallback == null){
+            if(userPrincipal.getUserInfo().getUser_type() == UserType.TYPE_SUPER){
+//            menuList = this.menuCacheProvider.getMenuTree(null, false, true);
+                menuList = this.menuCacheProvider.getMenuList(null, MenuUtils.MENU_SCOPE_PLATFORM);
+            } else {
+                // 鑾峰緱褰撳墠鐢ㄦ埛鎵�灞炵殑瑙掕壊ID闆嗗悎
+//            List<String> menuIdList = this.menuService.queryRoleMenuIdList(userPrincipal.getRoleIdList());
+//            menuList = this.menuCacheProvider.getMenuTree(menuIdList, false, false);
+              // 2023-06-01 澧炲姞椤剁骇鍗曚綅鍙娇鐢ㄧ殑鑿滃崟鑼冨洿銆�
+              int menuScope = this.getDeptCacheProvider().getDept(userPrincipal.getUserInfo().getOrg_id()).getMenu_type();
+              if(menuScope == MenuUtils.MENU_SCOPE_PLATFORM){
+                  // 骞冲彴鑿滃崟锛岄渶瑕佹牴鎹鑹叉煡璇�
+                  menuList = this.menuCacheProvider.getMenuList(userPrincipal.getRoleIdList(), menuScope);
+              } else {
+                  // 鍟嗘埛锛堥《绾ф満鏋勶級鐙珛鑿滃崟锛屼笉闇�瑕佽鑹�
+                  menuList = this.menuCacheProvider.getMenuList(null, menuScope);
+              }
+//            menuList = this.menuCacheProvider.getMenuList(userPrincipal.getRoleIdList(), menuScope);
+            }
+        } else {
+            // 2023-10-13
+            menuList = securityCallback.loadUserMenu(userPrincipal.getUserInfo(), userPrincipal.getRoleIdList());
+            if(this.logger.isDebugEnabled()){
+                logger.debug("瀛樺湪涓氬姟鑷畾涔夎彍鍗曞洖璋冿細{}", menuList);
+            }
+        }
+        if(menuList != null){
+            // 杩囨护鎺夋寜閽潈闄愶紝鍓嶇鍙渶瑕佽彍鍗曪紝鎸夐挳鏉冮檺鍦╬ermisstion涓帶鍒�
+            SystemMenu menu = null;
+            for(Iterator<SystemMenu> it = menuList.iterator(); it.hasNext();){
+                menu = it.next();
+                // 1.鍘绘帀鎸夐挳鑿滃崟锛屽悓鏃讹紝鍋滅敤鐨勮彍鍗曚篃瑕佸幓鎺夈��2023-05-14
+                // 2.涓嶈兘灞曠ず鐨勪篃瑕佸幓鎺夛紝is_show = 0
+                if(menu.getMenu_type().equals(MenuUtils.MENU_TYPE_BUTTON)
+                        || menu.getStatus().equals(MenuUtils.MENU_STATUS_DISABLED)
+                        || menu.getVisible().equals(MenuUtils.MENU_INVISIBLE)){
+                    it.remove();
+                }
+            }
+        }
+        return menuList;
+    }
+
+//    private String validateCaptcha(String username, String code, String uuid, CaptchaProvider<CaptchaResult> captchaProvider){
+//        if(StringUtils.isEmpty(uuid) || StringUtils.isEmpty(code)){
+//            return "璇疯緭鍏ラ獙璇佺爜";
+//        }
+//
+//        CaptchaResult captchaResult = new CaptchaResult();
+//        captchaResult.setUuid(uuid);
+//        captchaResult.setCode(code);
+//        boolean success = captchaProvider.validateCaptcha(captchaResult);
+//
+//        // 2023-04-07 璋冩暣锛屼娇鐢ㄦ彁渚涜�呭垽鏂獙璇佺爜鏄惁姝g‘銆�
+//        this.captchaCacheProvider.removeCacheData(Constants.CAPTCHA_CODE_PREFIX + uuid);// 鍒犻櫎缂撳瓨鐨勯獙璇佺爜
+//
+//        if(!success){
+//            logger.error("楠岃瘉鐮佹牎楠屽け璐�: code = " + code);
+//            return "楠岃瘉鐮侀敊璇�";
+//        }
+//        return null;
+//    }
+
+//    private void recordLoginInfo(String loginId, String status, String message, long userId, String uuid, String clientType){
+//        if(this.logProperties.isLoginEnabled()){
+//            logger.debug("寮傛璁板綍鐧诲綍鏃ュ織锛屽悗缁琛ュ厖:" + status + ", " + message);
+//            AsyncManager.me().execute(this.acquireLoginInfoTask(loginId, status, message, userId, uuid, clientType));
+//        }
+//    }
+//
+//    private TimerTask acquireLoginInfoTask(String loginId, String status, String message, Long userId
+//            , String uuid, String clientType){
+//        HttpServletRequest request = this.getRequest();
+//        final WebUserAgent webUserAgent = this.webAgentService.getWebUserAgent(request.getHeader("User-Agent"), request);
+//
+//        return new TimerTask() {
+//            @Override
+//            public void run() {
+//                S_login_info login_info = new S_login_info();
+//                login_info.setLogin_time(Long.parseLong(DateUtils.getDateTimeSecondForShow()));
+//                login_info.setUser_name(loginId);
+//                login_info.setMsg(message);
+//                login_info.setStatus(status);
+//                login_info.setInfo_id(NumberGenerator.getLongSequenceNumber());
+//                if(webUserAgent != null){
+//                    login_info.setLogin_location(webUserAgent.getLocation());
+//                    login_info.setBrowser(webUserAgent.getBrowserName());
+//                    login_info.setIpaddr(webUserAgent.getIp());
+//                    login_info.setOs(webUserAgent.getOsName());
+//                }
+//
+//                // 2023-03-23
+//                if(status.equals(String.valueOf(ResponseCode.SUCCESS.getCode()))){
+//                    // 鐧诲綍鎴愬姛鎵嶈褰晆uid鍏宠仈缂撳瓨
+//                    loginService.execUpdateUserLogin(userId, loginId, uuid, clientType, login_info);
+//                } else {
+//                    // 鐧诲綍澶辫触锛屼粎璁板綍鐧诲綍鏃ュ織
+//                    logService.execInsertLoginLog(login_info, userId);
+//                }
+//            }
+//        };
+//    }
+}
diff --git a/iplatform-base-security-consum/src/main/java/com/iplatform/security/event/RoleSecurityUpdateListener.java b/iplatform-base-security-consum/src/main/java/com/iplatform/security/event/RoleSecurityUpdateListener.java
new file mode 100644
index 0000000..9360832
--- /dev/null
+++ b/iplatform-base-security-consum/src/main/java/com/iplatform/security/event/RoleSecurityUpdateListener.java
@@ -0,0 +1,40 @@
+package com.iplatform.security.event;
+
+import com.iplatform.base.event.RoleSecurityChangeEvent;
+import com.walker.web.security.ResourceLoadProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.ApplicationListener;
+
+/**
+ * 瑙掕壊瀵瑰簲鏉冮檺鏇存柊鐩戝惉鍣紝鍦ㄨ鑹叉潈闄愪慨鏀瑰悗锛屼細瑙﹀彂璇ヤ簨浠舵潵鍝嶅簲銆�
+ * <p>濡傛灉涓嶉�氱煡閲嶆柊鍔犺浇锛屽垯瑙掕壊鍒嗚繃鏉冮檺鍚庯紝鐢ㄦ埛浠嶇劧鐪嬩笉鍒帮紙闇�瑕侀噸鏂板惎鍔級</p>
+ * @author shikeying
+ * @date 2023-05-07 绉绘鑰佷唬鐮�
+ */
+public class RoleSecurityUpdateListener implements ApplicationListener<RoleSecurityChangeEvent> {
+
+	private Logger logger = LoggerFactory.getLogger(getClass());
+
+//	private MySecurityMetadataSource securityMetaSource;
+//
+//	public void setSecurityMetaSource(MySecurityMetadataSource securityMetaSource) {
+//		assert (securityMetaSource != null);
+//		this.securityMetaSource = securityMetaSource;
+//	}
+
+	private ResourceLoadProvider resourceLoaderProvider;
+
+	public void setResourceLoaderProvider(ResourceLoadProvider securityMetaSource) {
+		this.resourceLoaderProvider = securityMetaSource;
+	}
+
+	@Override
+	public void onApplicationEvent(RoleSecurityChangeEvent event) {
+		resourceLoaderProvider.reloadResource();
+		logger.info("*************************************************");
+		logger.info("*  绯荤粺閲嶆柊鍔犺浇浜嗚鑹叉潈闄愭暟鎹�");
+		logger.info("*************************************************");
+	}
+
+}
diff --git a/iplatform-base-security-consum/src/main/java/com/iplatform/security/exception/PcUserStopAppException.java b/iplatform-base-security-consum/src/main/java/com/iplatform/security/exception/PcUserStopAppException.java
new file mode 100644
index 0000000..4d7dc11
--- /dev/null
+++ b/iplatform-base-security-consum/src/main/java/com/iplatform/security/exception/PcUserStopAppException.java
@@ -0,0 +1,20 @@
+package com.iplatform.security.exception;
+
+import org.springframework.security.core.AuthenticationException;
+
+/**
+ * PC锛堝悗鍙扮敤鎴凤級鏃犳硶璁块棶App寮傚父瀹氫箟銆�
+ * @author 鏃跺厠鑻�
+ * @date 2023-03-20
+ */
+public class PcUserStopAppException extends AuthenticationException {
+
+    public PcUserStopAppException(Throwable cause) {
+        super(MESSAGE, cause);
+    }
+    public PcUserStopAppException(String msg, Throwable cause) {
+        super(msg, cause);
+    }
+
+    public static final String MESSAGE = "闈濧pp鐢ㄦ埛鏃犳硶鐧诲綍鎵嬫満绔�!";
+}
diff --git a/iplatform-base-security-consum/src/main/java/com/iplatform/security/util/LoginCallbackUtils.java b/iplatform-base-security-consum/src/main/java/com/iplatform/security/util/LoginCallbackUtils.java
new file mode 100644
index 0000000..d98f9f1
--- /dev/null
+++ b/iplatform-base-security-consum/src/main/java/com/iplatform/security/util/LoginCallbackUtils.java
@@ -0,0 +1,69 @@
+package com.iplatform.security.util;
+
+import com.iplatform.base.PlatformLoginCallback;
+import com.iplatform.base.callback.PlatformCallbackPostProcessor;
+import com.iplatform.security.callback.EncryptPasswordLoginCallback;
+import com.iplatform.security.callback.MobilePassCaptchaLoginCallback;
+import com.iplatform.security.callback.NoneCaptchaLoginCallback;
+import com.iplatform.security.callback.SimplePasswordLoginCallback;
+import com.iplatform.security.callback.SmsCodeLoginCallback;
+import com.iplatform.security.callback.ThirdPartyLoginCallback;
+import com.iplatform.security.callback.WechatLoginCallback;
+import com.walker.web.CaptchaType;
+import com.walker.web.LoginType;
+import org.slf4j.ILoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 鐧诲綍鍥炶皟宸ュ叿绫汇��
+ * @author 鏃跺厠鑻�
+ * @date 2023-01-26
+ */
+public class LoginCallbackUtils {
+
+    protected static final Logger logger = LoggerFactory.getLogger(LoginCallbackUtils.class);
+
+//    public static final PlatformLoginCallback getLoginCallbackBean(UserType userType){
+//        if(userType == UserType.UserEquipment){
+//            throw new UnsupportedOperationException("鏆備笉鏀寔璁惧杩炴帴鐧诲綍鍥炶皟");
+//        } else if(userType == UserType.UserApp){
+//            return getLoginCallbackBean(LoginType.MOBILE);
+//        } else {
+//            return getLoginCallbackBean(LoginType.PC);
+//        }
+//    }
+
+    /**
+     * 鏍规嵁鐧诲綍绫诲瀷锛屾煡鎵剧櫥褰曞洖璋冨畾涔夊疄鐜般��
+     * @param loginType 鐧诲綍绫诲瀷锛屽弬鑰冿細{@linkplain LoginType}
+     * @param encryptPassword 濡傛灉瀵嗙爜鏂瑰紡锛屽瘑鐮佹槸鍚﹀姞瀵�
+     * @return
+     */
+    public static final PlatformLoginCallback getLoginCallbackBean(LoginType loginType, boolean encryptPassword, CaptchaType captchaType){
+        if(loginType == LoginType.UserPassword){
+            if(encryptPassword){
+                return PlatformCallbackPostProcessor.getCallbackMultipleBean(EncryptPasswordLoginCallback.class);
+            } else {
+                logger.error("'SimplePasswordLoginCallback'杩樻湭閰嶇疆锛屾槑鏂囧瘑鐮佺櫥褰曞凡涓嶅啀鏀寔锛佷粎鐢ㄤ簬娴嬭瘯銆�");
+                return PlatformCallbackPostProcessor.getCallbackMultipleBean(SimplePasswordLoginCallback.class);
+            }
+        } else if(loginType == LoginType.SmsCode){
+            return PlatformCallbackPostProcessor.getCallbackMultipleBean(SmsCodeLoginCallback.class);
+        } else if(loginType == LoginType.MobilePassword){
+            if(captchaType == CaptchaType.None){
+                return PlatformCallbackPostProcessor.getCallbackMultipleBean(NoneCaptchaLoginCallback.class);
+            } else {
+                return PlatformCallbackPostProcessor.getCallbackMultipleBean(MobilePassCaptchaLoginCallback.class);
+            }
+
+//            return PlatformCallbackPostProcessor.getCallbackMultipleBean(NoneCaptchaLoginCallback.class);
+        } else if(loginType == LoginType.ThirdParty){
+            return PlatformCallbackPostProcessor.getCallbackMultipleBean(ThirdPartyLoginCallback.class);
+        } else if(loginType == LoginType.Wechat){
+            return PlatformCallbackPostProcessor.getCallbackMultipleBean(WechatLoginCallback.class);
+        } else {
+            throw new UnsupportedOperationException("鏆備笉鏀寔鐧诲綍绫诲瀷:" + loginType);
+        }
+    }
+}
diff --git a/iplatform-base-security-consum/src/main/java/com/iplatform/security/util/MockPrincipalUtils.java b/iplatform-base-security-consum/src/main/java/com/iplatform/security/util/MockPrincipalUtils.java
new file mode 100644
index 0000000..cc1c880
--- /dev/null
+++ b/iplatform-base-security-consum/src/main/java/com/iplatform/security/util/MockPrincipalUtils.java
@@ -0,0 +1,53 @@
+package com.iplatform.security.util;
+
+import com.iplatform.base.DefaultUserPrincipal;
+import com.iplatform.model.po.S_user_core;
+import com.walker.infrastructure.utils.DateUtils;
+import com.walker.web.DataStatus;
+import com.walker.web.UserPrincipal;
+import com.walker.web.UserType;
+
+public class MockPrincipalUtils {
+
+//    /**
+//     * 姝e紡浠g爜锛屽垱寤鸿秴绾х鐞嗗憳鐢ㄦ埛鐧诲綍瀵硅薄
+//     * @return
+//     */
+//    public static final UserPrincipal<S_user_core> createSupervisor(String supervisorPassword){
+//        S_user_core userCore = new S_user_core();
+//        userCore.setId(Constants.SUPERVISOR_ID);
+////        userCore.setCreateTime(DateUtils.getDateTimeNumber(System.currentTimeMillis()));
+//        userCore.setCreate_time(DateUtils.getDateTimeNumber(System.currentTimeMillis()));
+//        userCore.setStatus(DataStatus.CONST_NORMAL);
+//        userCore.setUser_name(Constants.SUPERVISOR_NAME_DEFAULT);
+//        userCore.setNick_name(Constants.SUPERVISOR_NAME_ZH);
+////        userCore.setPassword("123456"); // 杩欓噷瑕佷慨鏀癸紝搴旇瀛樺偍鍔犲瘑杩囧悗鐨勫瘑鐮佷俊鎭�
+//        userCore.setPassword(supervisorPassword);
+//        userCore.setUser_type(UserType.TYPE_SUPER);
+//
+//        DefaultUserPrincipal userPrincipal = new DefaultUserPrincipal(userCore);
+//        return userPrincipal;
+//    }
+
+    /**
+     * 妯℃嫙涓�涓櫘閫氱敤鎴�
+     * @param id 鐢ㄦ埛ID(浠ュ強鐧诲綍ID)
+     * @return
+     */
+    @Deprecated
+    public static final UserPrincipal<S_user_core> createNormalUser(String id){
+        S_user_core userCore = new S_user_core();
+        userCore.setId(Long.parseLong(id));
+//        userCore.setCreateTime(DateUtils.getDateTimeNumber(System.currentTimeMillis()));
+        userCore.setCreate_time(DateUtils.getDateTimeNumber(System.currentTimeMillis()));
+        userCore.setStatus(DataStatus.CONST_NORMAL);
+        userCore.setUser_name(id);
+        userCore.setNick_name("婕旂ず鐢ㄦ埛");
+        userCore.setPassword("123456"); // 杩欓噷瑕佷慨鏀癸紝搴旇瀛樺偍鍔犲瘑杩囧悗鐨勫瘑鐮佷俊鎭�
+        userCore.setUser_type(UserType.TYPE_NORMAL);
+
+        DefaultUserPrincipal userPrincipal = new DefaultUserPrincipal(userCore);
+        return userPrincipal;
+    }
+
+}
diff --git a/iplatform-base-security-consum/src/main/java/com/iplatform/security/util/ResourceLoaderUtils.java b/iplatform-base-security-consum/src/main/java/com/iplatform/security/util/ResourceLoaderUtils.java
new file mode 100644
index 0000000..f4a8dbf
--- /dev/null
+++ b/iplatform-base-security-consum/src/main/java/com/iplatform/security/util/ResourceLoaderUtils.java
@@ -0,0 +1,5 @@
+package com.iplatform.security.util;
+
+public class ResourceLoaderUtils {
+
+}
diff --git a/iplatform-base-security-consum/src/main/java/com/iplatform/security/util/SecurityConfigUtils.java b/iplatform-base-security-consum/src/main/java/com/iplatform/security/util/SecurityConfigUtils.java
new file mode 100644
index 0000000..f2ecff6
--- /dev/null
+++ b/iplatform-base-security-consum/src/main/java/com/iplatform/security/util/SecurityConfigUtils.java
@@ -0,0 +1,58 @@
+package com.iplatform.security.util;
+
+import com.iplatform.base.captcha.JigsawCaptchaProvider;
+import com.iplatform.base.captcha.NoneCaptchaProvider;
+import com.iplatform.security.config.SecurityProperties;
+import com.walker.web.CaptchaProvider;
+import com.walker.web.CaptchaResult;
+import com.walker.web.CaptchaType;
+import com.walker.web.ClientType;
+import com.walker.web.captcha.SlideCaptchaProvider;
+
+public class SecurityConfigUtils {
+
+    /**
+     * 鏍规嵁璁惧绫诲瀷锛岃繑鍥瀟oken澶辨晥鏃堕棿锛堝垎閽燂級
+     * @param clientType
+     * @param securityProperties
+     * @return
+     * @date 2023-03-28
+     */
+    public static final long getTokenExpireMinutes(String clientType, SecurityProperties securityProperties){
+        if(clientType.equals(ClientType.INDEX_PC)){
+            return securityProperties.getTokenExpireWeb();
+        } else {
+            return securityProperties.getTokenExpireMobile();
+        }
+    }
+
+    /**
+     * 鏍规嵁'鐧诲綍鍥炶皟鏂瑰紡'鏌ユ壘闇�瑕佽閰嶇殑'楠岃瘉鐮佺被鍨�'銆�
+     * @param loginCaptchaUserPass
+     * @param smsCaptchaProvider
+     * @param imageCaptchaProvider
+     * @return
+     * @date 2023-03-14
+     */
+    public static final CaptchaProvider<CaptchaResult> findCaptchaProvider(String loginCaptchaUserPass
+            , CaptchaProvider<CaptchaResult> smsCaptchaProvider
+            , CaptchaProvider<CaptchaResult> imageCaptchaProvider
+            , JigsawCaptchaProvider jigsawCaptchaProvider){
+        CaptchaProvider<CaptchaResult> captchaProvider = null;
+        CaptchaType captchaType = CaptchaType.getType(loginCaptchaUserPass);
+        if(captchaType == CaptchaType.InputCode){
+            captchaProvider = imageCaptchaProvider;
+        } else if(captchaType == CaptchaType.SmsCode){
+            captchaProvider = smsCaptchaProvider;
+        } else if(captchaType == CaptchaType.Slide){
+            captchaProvider = new SlideCaptchaProvider();
+        } else if(captchaType == CaptchaType.Jigsaw){
+            captchaProvider = jigsawCaptchaProvider;
+        } else if(captchaType == CaptchaType.None){
+            captchaProvider = new NoneCaptchaProvider();
+        } else {
+            throw new UnsupportedOperationException("涓嶆敮鎸佺殑CaptchaType:" + loginCaptchaUserPass);
+        }
+        return captchaProvider;
+    }
+}
diff --git a/iplatform-base-security-consum/src/test/java/com/iplatform/security/TestSecurity.java b/iplatform-base-security-consum/src/test/java/com/iplatform/security/TestSecurity.java
new file mode 100644
index 0000000..a6cf075
--- /dev/null
+++ b/iplatform-base-security-consum/src/test/java/com/iplatform/security/TestSecurity.java
@@ -0,0 +1,37 @@
+package com.iplatform.security;
+
+import com.iplatform.base.util.PlatformRSAUtils;
+import com.walker.infrastructure.utils.Base64;
+import com.walker.infrastructure.utils.Base64Utils;
+import com.walker.infrastructure.utils.RSAUtil;
+import org.junit.Test;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+
+import java.security.KeyFactory;
+import java.security.PrivateKey;
+import java.security.spec.PKCS8EncodedKeySpec;
+
+public class TestSecurity {
+
+//    @Test
+    public void testDecryptPassword() throws Exception{
+        String encodePass = "DOEUaXiOa0y8Kq0De+P4OL/bdydlEFC+330I2lmXbz8VwHJYugLV/IPeXp31fZ5yOQvelMLwDutNtgQaRVS9L8n5ctjpYQZC3HAVDZ+6sXhE3TIH14Q8S3RhD3kE8iBVKrWd7423iCjflNwUPedFcQ0zVpJt3pC3wvDUayXIJnI=";
+//        String decode = Base64.decodeBase64(encode.getBytes(StandardCharsets.UTF_8));
+
+        byte[] keyBytes = Base64Utils.decode(PlatformRSAUtils.PRIK);
+        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
+        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+        PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);
+
+        String password = RSAUtil.decrypt(privateK, Base64.decode(encodePass.getBytes()));
+        System.out.println(password);
+    }
+
+//    @Test
+    public void testGeneratePassword(){
+        String raw = "123456";
+        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
+        String encrypt = passwordEncoder.encode(raw);
+        System.out.println("encrypt = " + encrypt);
+    }
+}
diff --git a/pom.xml b/pom.xml
index fe3cc59..7e7008d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -7,6 +7,7 @@
     <module>deploy-jar-single</module>
     <module>consum-base</module>
     <module>consum-model-pojo</module>
+    <module>iplatform-base-security-consum</module>
   </modules>
 
   <parent>
@@ -44,6 +45,12 @@
         <version>${consum-model-pojo.version}</version>
       </dependency>
 
+      <dependency>
+        <groupId>com.iplatform</groupId>
+        <artifactId>iplatform-base-security-consum</artifactId>
+        <version>1.0.0-SNAPSHOT</version>
+      </dependency>
+
     </dependencies>
   </dependencyManagement>
 

--
Gitblit v1.9.1