Ver Fonte

门户钉钉免登录

zhangcl há 6 horas atrás
pai
commit
6616591601

+ 109 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/string/StrUtils.java

@@ -9,6 +9,7 @@ import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collection;
 import java.util.List;
 import java.util.List;
 import java.util.Set;
 import java.util.Set;
+import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
 
 
 /**
 /**
@@ -104,4 +105,112 @@ public class StrUtils {
         });
         });
     }
     }
 
 
+    /**
+     *
+     * @param value
+     * @return
+     */
+    public static String stripXSS(String value) {
+        if (value != null) {
+            value = value.replaceAll("", "");
+            // Avoid anything between script tags
+            Pattern scriptPattern = Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE);
+            value = scriptPattern.matcher(value).replaceAll("");
+            // Avoid anything in a src='...' type of expression
+            scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'",
+                    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
+            value = scriptPattern.matcher(value).replaceAll("");
+            scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"",
+                    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
+            value = scriptPattern.matcher(value).replaceAll("");
+            // Remove any lonesome </script> tag
+            scriptPattern = Pattern.compile("</script>", Pattern.CASE_INSENSITIVE);
+            value = scriptPattern.matcher(value).replaceAll("");
+            // Remove any lonesome <script ...> tag
+            scriptPattern = Pattern.compile("<script(.*?)>",
+                    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
+            value = scriptPattern.matcher(value).replaceAll("");
+            // Avoid eval(...) expressions
+            scriptPattern = Pattern.compile("eval\\((.*?)\\)",
+                    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
+            value = scriptPattern.matcher(value).replaceAll("");
+            // Avoid expression(...) expressions
+            scriptPattern = Pattern.compile("expression\\((.*?)\\)",
+                    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
+            value = scriptPattern.matcher(value).replaceAll("");
+            // Avoid javascript:... expressions
+            scriptPattern = Pattern.compile("javascript:", Pattern.CASE_INSENSITIVE);
+            value = scriptPattern.matcher(value).replaceAll("");
+            // Avoid vbscript:... expressions
+            scriptPattern = Pattern.compile("vbscript:", Pattern.CASE_INSENSITIVE);
+            value = scriptPattern.matcher(value).replaceAll("");
+            // Avoid οnlοad= expressions
+            scriptPattern = Pattern.compile("onload(.*?)=",
+                    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
+            value = scriptPattern.matcher(value).replaceAll("");
+
+            scriptPattern = Pattern.compile("<iframe>(.*?)</iframe>", Pattern.CASE_INSENSITIVE);
+            value = scriptPattern.matcher(value).replaceAll("");
+
+            scriptPattern = Pattern.compile("</iframe>", Pattern.CASE_INSENSITIVE);
+            value = scriptPattern.matcher(value).replaceAll("");
+            // Remove any lonesome <script ...> tag
+            scriptPattern = Pattern.compile("<iframe(.*?)>",
+                    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
+            value = scriptPattern.matcher(value).replaceAll("");
+        }
+        return value;
+    }
+
+    public static String escape(String s) {
+        StringBuilder sb = new StringBuilder(s.length() + 16);
+        for (int i = 0; i < s.length(); i++) {
+            char c = s.charAt(i);
+            switch (c) {
+                case '>':
+                    sb.append('>');// 全角大于号
+                    break;
+                case '<':
+                    sb.append('<');// 全角小于号
+                    break;
+                case '\'':
+                    sb.append('‘');// 全角单引号
+                    break;
+                case '\"':
+                    sb.append('“');// 全角双引号
+                    break;
+                case '\\':
+                    sb.append('\');// 全角斜线
+                    break;
+                case '%':
+                    sb.append('%'); // 全角冒号
+                    break;
+                default:
+                    sb.append(c);
+                    break;
+            }
+
+        }
+        return sb.toString();
+    }
+
+    /**
+     * 将容易引起xss漏洞的半角字符直接替换成全角字符
+     *
+     * @param s
+     * @return
+     */
+    public static String xssEncode(String s) {
+        if (s == null || s.isEmpty()) {
+            return s;
+        }
+
+        String result = stripXSS(s);
+        if (null != result) {
+            result = escape(result);
+        }
+
+        return result;
+    }
+
 }
 }

+ 8 - 0
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java

@@ -212,4 +212,12 @@ public class AuthController {
         return crmSuccess(authService.crmGetUser(reqVO));
         return crmSuccess(authService.crmGetUser(reqVO));
     }
     }
 
 
+    @PostMapping("/h5SocialLogin")
+    @PermitAll
+    @Operation(summary = "h5微应用 钉钉快捷登录,code 免登录授权码", description = "适合已经配置了钉钉手机号的用户")
+    public CommonResult<AuthLoginRespVO> h5SocialLogin(@RequestBody @Valid AuthSocialLoginReqVO reqVO) {
+        AuthLoginRespVO authLoginRespVO = authService.h5SocialLogin(reqVO);
+        return success(authLoginRespVO);
+    }
+
 }
 }

+ 2 - 0
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/enums/logger/LoginLogTypeEnum.java

@@ -14,6 +14,8 @@ public enum LoginLogTypeEnum {
     LOGIN_SOCIAL(101), // 使用社交登录
     LOGIN_SOCIAL(101), // 使用社交登录
     LOGIN_MOBILE(103), // 使用手机登陆
     LOGIN_MOBILE(103), // 使用手机登陆
     LOGIN_SMS(104), // 使用短信登陆
     LOGIN_SMS(104), // 使用短信登陆
+    LOGIN_DING_APP(105), // 钉钉APP
+    LOGIN_DING_H5(106), // 钉钉H5微应用
 
 
     LOGOUT_SELF(200),  // 自己主动登出
     LOGOUT_SELF(200),  // 自己主动登出
     LOGOUT_DELETE(202), // 强制退出
     LOGOUT_DELETE(202), // 强制退出

+ 8 - 0
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthService.java

@@ -105,4 +105,12 @@ public interface AdminAuthService {
      * @param reqVO 工号
      * @param reqVO 工号
      */
      */
     String crmGetUser(AuthCrmLoginReqVO reqVO);
     String crmGetUser(AuthCrmLoginReqVO reqVO);
+
+    /**
+     * h5微应用 钉钉快捷登录,code 免登录授权码
+     *
+     * @param reqVO 登录信息
+     * @return 登录结果
+     */
+    AuthLoginRespVO h5SocialLogin(@Valid AuthSocialLoginReqVO reqVO);
 }
 }

+ 39 - 0
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java

@@ -7,6 +7,7 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
 import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
 import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
 import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
 import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
+import cn.iocoder.yudao.framework.common.util.string.StrUtils;
 import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
 import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
 import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
 import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
 import cn.iocoder.yudao.module.system.api.logger.dto.LoginLogCreateReqDTO;
 import cn.iocoder.yudao.module.system.api.logger.dto.LoginLogCreateReqDTO;
@@ -405,4 +406,42 @@ public class AdminAuthServiceImpl implements AdminAuthService {
         // 查询 userId 对应的员工工号
         // 查询 userId 对应的员工工号
         return user.getUsername();
         return user.getUsername();
     }
     }
+
+    @Override
+    public AuthLoginRespVO h5SocialLogin(AuthSocialLoginReqVO reqVO) {
+        // h5页面获取免登录授权码code 后台通过code查询用户信息
+        String validCode = StrUtils.xssEncode(reqVO.getCode());
+        try {
+            // 钉钉用户id
+            String userId = DingtalkUtil.getUserIdByAuthCode(validCode);
+            if (StrUtil.isBlank(userId)) {
+                // 查询不到用户详情 返回 登录失败
+                throw exception(USER_NOT_EXISTS);
+            }
+            // 根据钉钉用户id 查询用户详情
+            OapiV2UserGetResponse.UserGetResponse userDetail = DingtalkUtil.getUserDetail(userId);
+            if (ObjUtil.isEmpty(userDetail)) {
+                // 查询不到用户详情 返回 登录失败
+                throw exception(USER_NOT_EXISTS);
+            }
+            // 工号
+            String jobNumber = userDetail.getJobNumber();
+            // 手机号
+            String mobile = userDetail.getMobile();
+            if (StrUtil.isBlank(mobile)) {
+                throw exception(USER_NOT_EXISTS);
+            }
+            // 查询当前用户表中 此手机号 是否存在
+            AdminUserDO user = userService.getUserByMobile(mobile);
+            if (ObjUtil.isEmpty(user)) {
+                throw exception(USER_NOT_EXISTS);
+            }
+            // 创建 Token 令牌,记录登录日志 h5钉钉微应用登录
+            return createTokenAfterLoginSuccess(user.getId(), user.getUsername(), LoginLogTypeEnum.LOGIN_DING_H5);
+        } catch (Exception e) {
+            // 调用钉钉接口报错 提示 登录失败
+            e.printStackTrace();
+            throw exception(USER_NOT_EXISTS);
+        }
+    }
 }
 }

+ 3 - 3
yudao-server/src/main/resources/application-dev.yaml

@@ -238,9 +238,9 @@ portal:
   code: cc99d802-ce5c-5f62-b037-9a00726e7109
   code: cc99d802-ce5c-5f62-b037-9a00726e7109
 
 
 dingtalk:
 dingtalk:
-  AGENT_ID: 3687646006  # DeepOil 微应用 agent_id
-  APP_KEY: dingmr9ez0ecgbmscfeb # 钉钉微应用 appkey
-  APP_SECRET: VhG_zMdTvIBwA_0Ef8FJ0foH3VYYo5T-kw0ukX_PBA8Ah1xl7AjDw5RVYCU0DTpe # 钉钉微应用 appkey
+  AGENT_ID: 4112589253  # DeepOil 微应用 AgentId
+  APP_KEY: dingcnw10hmrqqkh28fw # 钉钉微应用 AppKey
+  APP_SECRET: U6iImdOGE3SKDS8jmNNdmZspECTVozKzanw3eEzSn-icDHDdJ438OO3RXr4lKte9 # 钉钉微应用 AppSecret
   GET_ACCESS_TOKEN_URL: https://oapi.dingtalk.com/gettoken  # 获取access_token
   GET_ACCESS_TOKEN_URL: https://oapi.dingtalk.com/gettoken  # 获取access_token
   URL_GET_USERINFO_BYCODE: https://oapi.dingtalk.com/sns/getuserinfo_bycode # 通过二维码扫码获取UNIONID
   URL_GET_USERINFO_BYCODE: https://oapi.dingtalk.com/sns/getuserinfo_bycode # 通过二维码扫码获取UNIONID
   URL_GET_USERINFO_BYUNIONID: https://oapi.dingtalk.com/topapi/user/getbyunionid # 通过UNIONID获取用户信息
   URL_GET_USERINFO_BYUNIONID: https://oapi.dingtalk.com/topapi/user/getbyunionid # 通过UNIONID获取用户信息