فهرست منبع

嵌入钉钉,实现免登录授权

huangguoce 1 هفته پیش
والد
کامیت
fa03c09180
6فایلهای تغییر یافته به همراه188 افزوده شده و 8 حذف شده
  1. 97 1
      App.vue
  2. 21 0
      api/auth/loginService.js
  3. 19 6
      common/auth.js
  4. 13 0
      package-lock.json
  5. 1 0
      package.json
  6. 37 1
      pages/login/login.vue

+ 97 - 1
App.vue

@@ -2,6 +2,8 @@
 	import Vue from 'vue'
     import BASE_URL from './config.js'
     import {mapActions} from 'vuex'
+    import loginService from '@/api/auth/loginService'
+    import * as dd from 'dingtalk-jsapi'
 	export default {
 		onLaunch: function() {
 			uni.getSystemInfo({
@@ -114,8 +116,12 @@
 			console.log('App Hide')
 		},
         created: async function() {
+	
+            const urlParams = this.getUrlParams();
+            if (await this.tryDingTalkAutoLogin(urlParams)) {
+                return;
+            }
             // 获取 URL 中的 code 参数
-            const urlParams = new URLSearchParams(window.location.search);
             const code = urlParams.get('code');
 
             console.log('传入 code -------');
@@ -192,6 +198,9 @@
             // 获取 URL 中的 'flow' 参数
             const flowParam = this.$route.query.flow;
             // 将 URL 编码的 'flow' 参数解析为 JSON 对象
+            if (!flowParam) {
+                return;
+            }
             const flowObject = JSON.parse(decodeURIComponent(flowParam));
             console.log("flowObject.openId---> ", flowObject.openId)
             if (flowObject.openId) {
@@ -212,6 +221,93 @@
         },
         methods: {
             ...mapActions(['refreshUserInfo']),
+            getUrlParams() {
+                const params = new URLSearchParams(window.location.search || '');
+                const hash = window.location.hash || '';
+                const hashQueryIndex = hash.indexOf('?');
+                if (hashQueryIndex > -1) {
+                    const hashParams = new URLSearchParams(hash.substring(hashQueryIndex + 1));
+                    hashParams.forEach((value, key) => {
+                        if (!params.has(key)) {
+                            params.set(key, value);
+                        }
+                    });
+                }
+                return params;
+            },
+            isDingTalkEnv() {
+                return /DingTalk/i.test(window.navigator.userAgent || '');
+            },
+            loadDingTalkJs() {
+                return Promise.resolve(dd);
+            },
+            requestDingTalkAuthCode(corpId) {
+                return new Promise((resolve, reject) => {
+                    if (!dd  ) {
+                        reject(new Error('钉钉资源未加载成功,请联系管理员'));
+                        return;
+                    }
+					dd.getAuthCode({
+						corpId: corpId,
+						onSuccess: (res) => resolve(res.code || res.authCode),
+						onFail: reject
+					});
+                    dd.error(reject);
+                });
+            },
+            async handleDingTalkLoginSuccess(data) {
+                this.$store.commit('SET_TOKEN', data.token);
+                await this.refreshUserInfo();
+            },
+            async tryDingTalkAutoLogin(urlParams) {
+                if (!this.isDingTalkEnv()) {
+                    return false;
+                }
+                if (this.$store.state.user.token) {
+                    return true;
+                }
+		
+                const tenantId = urlParams.get('tenantId') || uni.getStorageSync('dingTalkTenantId') || '10009';
+
+                try {
+                    const clientConfig = await loginService.dingTalkClientConfig(tenantId);
+	
+                    if (!clientConfig || !clientConfig.corpId) {
+					
+                        throw new Error('DingTalk corpId is missing');
+                    }
+					
+                    await this.loadDingTalkJs();
+					
+                    const authCode = await this.requestDingTalkAuthCode(clientConfig.corpId);
+			
+                    const loginResult = await loginService.dingTalkLogin({
+                        authCode: authCode,
+                        tenantId: tenantId
+                    });
+			
+                    if (loginResult.bindRequired) {
+                        uni.setStorageSync('dingTalkBindKey', loginResult.bindKey);
+                        uni.setStorageSync('dingTalkTenantId', loginResult.tenantId || tenantId);
+                        uni.reLaunch({
+                            url: '/pages/login/login?bind=dingtalk'
+                        });
+                        return true;
+                    }
+                    await this.handleDingTalkLoginSuccess(loginResult);
+                    uni.reLaunch({
+                        url: '/pages/index/index'
+                    });
+                } catch (e) {
+					if(!e.isTrusted){
+						uni.showToast({
+						    title: '钉钉异常,请联系管理员',
+						    icon: 'none'
+						});
+					}
+                }
+                return true;
+            },
         }
 
 	}

+ 21 - 0
api/auth/loginService.js

@@ -22,6 +22,27 @@ export default {
       method: 'get'
     })
   },
+  dingTalkClientConfig: function (tenantId) {
+    return request({
+      url: prefix + "/user/sys/dingtalk/clientConfig",
+      method: "get",
+      params: { tenantId: tenantId },
+    })
+  },
+  dingTalkLogin: function (data) {
+    return request({
+      url: prefix + "/user/sys/dingtalk/login",
+      method: "post",
+      data: data,
+    })
+  },
+  dingTalkBindLogin: function (data) {
+    return request({
+      url: prefix + "/user/sys/dingtalk/bindLogin",
+      method: "post",
+      data: data,
+    })
+  },
   getLoginCodeNumber: function (userName) {
     return request({
       url: prefix + "/user/getLoginCodeNumber",

+ 19 - 6
common/auth.js

@@ -5,9 +5,22 @@ const userInfoKey = 'WMS-userinfo'
 const permissionsKey = 'WMS-permission'
 import store from '@/store'
 
+function getStorage(key, defaultValue) {
+	if (typeof key !== 'string' || !key || key === 'undefined') {
+		return defaultValue;
+	}
+	try {
+		const value = uni.getStorageSync(key);
+		return value === undefined || value === null ? defaultValue : value;
+	} catch (e) {
+		console.error('getStorageSync failed:', key, e);
+		return defaultValue;
+	}
+}
+
 // 获取token值
 function getUserToken(){
-	return uni.getStorageSync(tokenKey);
+	return getStorage(tokenKey, null);
 }
 
 function setUserToken(token){
@@ -21,7 +34,7 @@ function removeUserToken(){
 
 // 获取用户名
 function getUsername(){
-	return uni.getStorageSync(usernameKey);
+	return getStorage(usernameKey, null);
 }
 
 function setUsername(username){
@@ -34,7 +47,7 @@ function removeUsername(){
 
 // 获取用户信息
 function getUserInfo(){
-	return uni.getStorageSync(userInfoKey);
+	return getStorage(userInfoKey, {});
 }
 
 function setUserInfo(userinfo){
@@ -47,7 +60,7 @@ function removeUserInfo(){
 
 // 获取用户权限
 function getPermissions(){
-	return uni.getStorageSync(permissionsKey);
+	return getStorage(permissionsKey, []);
 }
 
 function setPermissions(permissions){
@@ -58,7 +71,7 @@ function removePermissions(){
 	uni.removeStorageSync(permissionsKey);
 }
 function hasPermission (key) {
-  return uni.getStorageSync(permissionsKey).indexOf(key) !== -1 || false
+  return getStorage(permissionsKey, []).indexOf(key) !== -1 || false
 }
 
 function checkLogin () {
@@ -108,4 +121,4 @@ export {
 	removePermissions,
 	hasPermission,
 	checkLogin
-}
+}

+ 13 - 0
package-lock.json

@@ -188,6 +188,14 @@
       "resolved": "https://registry.npmmirror.com/digest-header/-/digest-header-1.1.0.tgz",
       "integrity": "sha512-glXVh42vz40yZb9Cq2oMOt70FIoWiv+vxNvdKdU8CwjLad25qHM3trLxhl9bVjdr6WaslIXhWpn0NO8T/67Qjg=="
     },
+    "dingtalk-jsapi": {
+      "version": "3.2.9",
+      "resolved": "https://registry.npmmirror.com/dingtalk-jsapi/-/dingtalk-jsapi-3.2.9.tgz",
+      "integrity": "sha512-VLt8co92z29bdguxUvJLnhpQn7WFjb5rJTODDczieS7I0yyWj5+KwF04sWfMvyIKX0MQPVL++Fyo6z2JucFpgQ==",
+      "requires": {
+        "promise-polyfill": "^7.1.0"
+      }
+    },
     "dom-zindex": {
       "version": "1.0.4",
       "resolved": "https://registry.npmmirror.com/dom-zindex/-/dom-zindex-1.0.4.tgz",
@@ -477,6 +485,11 @@
       "resolved": "https://registry.npmmirror.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
       "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
     },
+    "promise-polyfill": {
+      "version": "7.1.2",
+      "resolved": "https://registry.npmmirror.com/promise-polyfill/-/promise-polyfill-7.1.2.tgz",
+      "integrity": "sha512-FuEc12/eKqqoRYIGBrUptCBRhobL19PS2U31vMNTfyck1FxPyMfgsXyW4Mav85y/ZN1hop3hOwRlUDok23oYfQ=="
+    },
     "pump": {
       "version": "3.0.0",
       "resolved": "https://registry.npmmirror.com/pump/-/pump-3.0.0.tgz",

+ 1 - 0
package.json

@@ -5,6 +5,7 @@
   "main": "main.js",
   "dependencies": {
     "ali-oss": "^6.18.1",
+    "dingtalk-jsapi": "^3.2.9",
     "element-ui": "^2.15.14",
     "lodash": "^4.17.20",
     "lodash.pick": "^4.4.0",

+ 37 - 1
pages/login/login.vue

@@ -149,17 +149,50 @@
 		},
 		created() {
 			this.getCaptcha()
+
 		},
 		methods: {
 			...mapActions(['refreshUserInfo']),
+			safeGetStorage(key, defaultValue = '') {
+				if (typeof key !== 'string' || !key || key === 'undefined') {
+					return defaultValue;
+				}
+				try {
+					const value = uni.getStorageSync(key);
+					return value === undefined || value === null ? defaultValue : value;
+				} catch (e) {
+					console.error('getStorageSync failed:', key, e);
+					return defaultValue;
+				}
+			},
 		  // 登录
 		  bindLogin() {
+			  console.log(this.passwordErrorCount)
+			  console.log(this.passwordErrorCount)
+			  console.log(this.passwordErrorCount)
+			  console.log(this.passwordErrorCount)
+
 				/**
 				 * 客户端对账号信息进行一些必要的校验。
 				 * 实际开发中,根据业务需要进行处理,这里仅做示例。
 				 */
 			this.$refs.uForm.validate().then(res => {
-				this.inputForm.openId = uni.getStorageSync('openId');
+				const dingTalkBindKey = this.safeGetStorage('dingTalkBindKey');
+				if (dingTalkBindKey) {
+					this.inputForm.dingTalkBindKey = dingTalkBindKey;
+					this.inputForm.tenantId = this.safeGetStorage('dingTalkTenantId', '10009') || '10009';
+					loginService.dingTalkBindLogin(this.inputForm).then((data) => {
+						uni.removeStorageSync('dingTalkBindKey');
+						this.$store.commit('SET_TOKEN', data.token);
+						this.refreshUserInfo();
+						this.$router.push('/pages/index/index');
+					}).catch(e => {
+						this.passwordErrorCount++;
+						console.error(e)
+					})
+					return;
+				}
+				this.inputForm.openId = this.safeGetStorage('openId');
 				loginService.login(this.inputForm).then((data) => {
 				  this.$store.commit('SET_TOKEN',data.token);
 				  this.refreshUserInfo();
@@ -176,6 +209,9 @@
 						this.getCaptcha(); // 获取验证码
 					}
 					this.getCaptcha()
+					if(e.data.includes("请输入验证码")){
+						this.passwordErrorCount = 5
+					}
 					console.error(e)
 				})
 			})