| | |
| | | lastToken: null // ç¨äºæ£æµ token åå |
| | | } |
| | | }, |
| | | onLaunch: function() { |
| | | onLaunch: function(options) { |
| | | this.lastToken = getToken() |
| | | this.initApp() |
| | | this.initApp(options) |
| | | |
| | | // æ£æ¥å¹¶æ¸
çåå¨ç©ºé´ |
| | | this.checkStorage() |
| | |
| | | }, |
| | | methods: { |
| | | // åå§ååºç¨ |
| | | initApp() { |
| | | initApp(options) { |
| | | // åå§ååºç¨é
ç½® |
| | | this.initConfig() |
| | | // æ£æ¥ç¨æ·ç»å½ç¶æ |
| | | //#ifdef H5 |
| | | this.checkLogin() |
| | | //#endif |
| | | // æ£æ¥ç¨æ·ç»å½ç¶æå¹¶èªå¨è·³è½¬å°åéçç»å½é¡µé¢ |
| | | this.checkLoginAndRedirect(options) |
| | | |
| | | // 注æï¼ä¸å¨åºç¨å¯å¨æ¶èªå¨å¯å¨è½®è¯¢ |
| | | // åªæå¨ç¨æ·ä¸»å¨ç»å½æååæå¯å¨ï¼éè¿ user-login äºä»¶è§¦åï¼ |
| | |
| | | initConfig() { |
| | | this.globalData.config = config |
| | | }, |
| | | checkLogin() { |
| | | // æ£æ¥ç»å½ç¶æå¹¶èªå¨è·³è½¬å°åéçç»å½é¡µé¢ |
| | | checkLoginAndRedirect(options) { |
| | | if (!getToken()) { |
| | | // æ£æ¥è¿è¡ç¯å¢å¹¶è·³è½¬å°å¯¹åºçç»å½é¡µé¢ |
| | | // #ifdef MP-WEIXIN |
| | | // å¨å¾®ä¿¡å°ç¨åºç¯å¢ä¸ |
| | | try { |
| | | // è·åç³»ç»ä¿¡æ¯ |
| | | const systemInfo = uni.getSystemInfoSync() |
| | | console.log('ç³»ç»ä¿¡æ¯:', systemInfo) |
| | | |
| | | // æ£æ¥environmentåæ®µæ¯å¦ä¸ºwxwork |
| | | if (systemInfo.environment === 'wxwork') { |
| | | console.log('æ£æµå°ä¼ä¸å¾®ä¿¡ç¯å¢ï¼è·³è½¬å°ä¼ä¸å¾®ä¿¡å
ç»é¡µé¢') |
| | | // æé 另忰çURL |
| | | let url = '/pages/qylogin' |
| | | if (options && options.query) { |
| | | const queryParams = Object.keys(options.query).map(key => `${key}=${encodeURIComponent(options.query[key])}`).join('&') |
| | | if (queryParams) { |
| | | url += '?' + queryParams |
| | | } |
| | | } |
| | | this.$tab.reLaunch(url) |
| | | return |
| | | } else { |
| | | console.log('æ£æµå°æ®é微信ç¯å¢ï¼è·³è½¬å°å¾®ä¿¡ç»å½é¡µé¢') |
| | | // æé 另忰çURL |
| | | let url = '/pages/login' |
| | | if (options && options.query) { |
| | | const queryParams = Object.keys(options.query).map(key => `${key}=${encodeURIComponent(options.query[key])}`).join('&') |
| | | if (queryParams) { |
| | | url += '?' + queryParams |
| | | } |
| | | } |
| | | this.$tab.reLaunch(url) |
| | | return |
| | | } |
| | | } catch (e) { |
| | | console.error('è·åç³»ç»ä¿¡æ¯å¤±è´¥:', e) |
| | | // é»è®¤è·³è½¬å°æ®éç»å½é¡µé¢ |
| | | this.$tab.reLaunch('/pages/login') |
| | | } |
| | | // #endif |
| | | |
| | | // #ifndef MP-WEIXIN |
| | | // é微信å°ç¨åºç¯å¢ï¼è·³è½¬å°æ®éç»å½é¡µé¢ |
| | | console.log('é微信å°ç¨åºç¯å¢ï¼è·³è½¬å°æ®éç»å½é¡µé¢') |
| | | let url = '/pages/login' |
| | | if (options && options.query) { |
| | | const queryParams = Object.keys(options.query).map(key => `${key}=${encodeURIComponent(options.query[key])}`).join('&') |
| | | if (queryParams) { |
| | | url += '?' + queryParams |
| | | } |
| | | } |
| | | this.$tab.reLaunch(url) |
| | | // #endif |
| | | } |
| | | }, |
| | | |
| | | // 夿å½åæ¯å¦å¨ç»å½é¡µé¢ |
| | |
| | | } |
| | | }) |
| | | } |
| | | |
| | | // ä¼ä¸å¾®ä¿¡å
ç» |
| | | export function qyWechatAutoLogin(code) { |
| | | return request({ |
| | | url: '/system/qywechat/autoLogin', |
| | | headers: { |
| | | isToken: false |
| | | }, |
| | | method: 'post', |
| | | data: { code } |
| | | }) |
| | | } |
| | |
| | | "navigationBarTitleText": "ç»å½" |
| | | } |
| | | }, { |
| | | "path": "pages/qylogin", |
| | | "style": { |
| | | "navigationBarTitleText": "ä¼ä¸å¾®ä¿¡å
ç»" |
| | | } |
| | | }, { |
| | | "path": "pages/login/wechat", |
| | | "style": { |
| | | "navigationBarTitleText": "微信ç»å½" |
| | |
| | | } |
| | | |
| | | // æ£æ¥è®¢é
ç¶æï¼å
æ£æ¥æ¬å°ï¼åé¢ä¼æ£æ¥å¾®ä¿¡å®æ¹ç¶æï¼ |
| | | this.hasSubscribed = subscribeManager.checkLocalSubscribeStatus(); |
| | | this.hasSubscribed = true;//subscribeManager.checkLocalSubscribeStatus(); |
| | | |
| | | // èªå¨è®¢é
ï¼å¦ææªè®¢é
åæ¾ç¤ºç¡®è®¤å¼¹çªï¼ |
| | | this.autoSubscribeOnLaunch(); |
| | |
| | | isWechat: false, // æ¯å¦ä¸ºå¾®ä¿¡å°ç¨åºç¯å¢ |
| | | wechatOpenId: '', // 微信OpenID |
| | | wechatUnionId: '', // 微信UnionID |
| | | // 页é¢åæ° |
| | | pageOptions: {} |
| | | } |
| | | }, |
| | | onLoad(options) { |
| | | // ä¿å页é¢åæ° |
| | | this.pageOptions = options || {} |
| | | }, |
| | | created() { |
| | | this.getCode() |
| | |
| | | this.$store.dispatch('GetInfo').then(res => { |
| | | // 触åç»å½æåäºä»¶ï¼å¯å¨æ¶æ¯è½®è¯¢ |
| | | uni.$emit('user-login') |
| | | // æ£æ¥æ¯å¦æredirectåæ°æå®è·³è½¬é¡µé¢ |
| | | if (this.pageOptions.redirect) { |
| | | // è§£ç redirectåæ° |
| | | const redirectUrl = decodeURIComponent(this.pageOptions.redirect) |
| | | this.$tab.reLaunch(redirectUrl) |
| | | } else { |
| | | // é»è®¤è·³è½¬å°é¦é¡µ |
| | | this.$tab.reLaunch('/pages/index') |
| | | } |
| | | }) |
| | | }, |
| | | |
| | |
| | | const { setToken } = require('@/utils/auth') |
| | | setToken(token) |
| | | |
| | | this.loginSuccess() |
| | | // æ£æ¥æ¯å¦æredirectåæ°æå®è·³è½¬é¡µé¢ |
| | | if (this.pageOptions.redirect) { |
| | | // è§£ç redirectåæ° |
| | | const redirectUrl = decodeURIComponent(this.pageOptions.redirect) |
| | | this.$tab.reLaunch(redirectUrl) |
| | | } else { |
| | | // é»è®¤è·³è½¬å°é¦é¡µ |
| | | this.$tab.reLaunch('/pages/index') |
| | | } |
| | | } else { |
| | | this.$modal.msgError(response.msg || 'ç»å½å¤±è´¥') |
| | | } |
| | |
| | | const { setToken } = require('@/utils/auth') |
| | | setToken(token) |
| | | |
| | | this.loginSuccess() |
| | | // æ£æ¥æ¯å¦æredirectåæ°æå®è·³è½¬é¡µé¢ |
| | | if (this.pageOptions.redirect) { |
| | | // è§£ç redirectåæ° |
| | | const redirectUrl = decodeURIComponent(this.pageOptions.redirect) |
| | | this.$tab.reLaunch(redirectUrl) |
| | | } else { |
| | | // é»è®¤è·³è½¬å°é¦é¡µ |
| | | this.$tab.reLaunch('/pages/index') |
| | | } |
| | | } else { |
| | | // OpenIDæªç»å®æéªè¯å¤±è´¥ï¼éè¦è·åææºå·ç»å® |
| | | console.log('该OpenIDå°æªç»å®æéªè¯å¤±è´¥ï¼éè¦è·åææºå·') |
| New file |
| | |
| | | <template> |
| | | <view class="container"> |
| | | <view class="loading-content" v-if="loading"> |
| | | <image class="loading-icon" src="/static/images/loading.gif"></image> |
| | | <text class="loading-text">æ£å¨ä¼ä¸å¾®ä¿¡å
ç»ä¸...</text> |
| | | </view> |
| | | |
| | | <view class="error-content" v-else-if="error"> |
| | | <image class="error-icon" src="/static/images/error.png"></image> |
| | | <text class="error-text">{{ errorMessage }}</text> |
| | | <button class="retry-btn" @click="retryLogin">éæ°å°è¯</button> |
| | | </view> |
| | | |
| | | <view class="success-content" v-else> |
| | | <image class="success-icon" src="/static/images/success.png"></image> |
| | | <text class="success-text">ä¼ä¸å¾®ä¿¡å
ç»æå</text> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | |
| | | <script> |
| | | import { qyWechatAutoLogin } from "@/api/login"; |
| | | |
| | | export default { |
| | | data() { |
| | | return { |
| | | loading: true, |
| | | error: false, |
| | | errorMessage: "", |
| | | // ä¿å页é¢åæ° |
| | | pageOptions: {}, |
| | | }; |
| | | }, |
| | | |
| | | onLoad(options) { |
| | | // ä¿å页é¢åæ° |
| | | this.pageOptions = options || {}; |
| | | // 页é¢å è½½æ¶æ§è¡å
ç»æµç¨ |
| | | this.qyWechatAutoLogin(); |
| | | }, |
| | | |
| | | methods: { |
| | | async getLoginCode() { |
| | | //è¿éè¦è°ç¨wx.qy.loginè·åcode,æ¯å¦æéæå°uni-appä¸å¢ |
| | | return new Promise((resolve, reject) => { |
| | | wx.qy.login({ |
| | | success: (res) => { |
| | | if (res.code) { |
| | | console.log("ä¼ä¸å¾®ä¿¡å°ç¨åº ---> codeï¼", res.code); |
| | | resolve(res.code); // è¿å code ç»å端 |
| | | } else { |
| | | reject(new Error("è·å code 失败ï¼" + res.errMsg)); |
| | | } |
| | | }, |
| | | fail: (err) => { |
| | | console.error("wx.qy.login è°ç¨å¤±è´¥ï¼", err); |
| | | // 常è§å¤±è´¥åå ï¼éä¼ä¸å¾®ä¿¡å®¢æ·ç«¯æå¼ãå°ç¨åºæªå
³èä¼ä¸å¾®ä¿¡ç |
| | | reject(new Error("ä¼ä¸å¾®ä¿¡ç»å½æ¥å£è°ç¨å¤±è´¥ï¼" + err.errMsg)); |
| | | }, |
| | | }); |
| | | }); |
| | | }, |
| | | /** |
| | | * ä¼ä¸å¾®ä¿¡å
ç»æµç¨ |
| | | */ |
| | | async qyWechatAutoLogin() { |
| | | try { |
| | | this.loading = true; |
| | | this.error = false; |
| | | |
| | | // #ifdef MP-WEIXIN |
| | | // å¨å¾®ä¿¡å°ç¨åºç¯å¢ä¸ï¼éè¿ä¼ä¸å¾®ä¿¡å
ç» |
| | | console.log("ä¼ä¸å¾®ä¿¡å°ç¨åºç¯å¢å
ç»"); |
| | | |
| | | // è·åURLåæ°ä¸çcode |
| | | const code = await this.getLoginCode(); |
| | | |
| | | if (!code) { |
| | | // å¦ææ²¡æcodeï¼å°è¯éè¿ä¼ä¸å¾®ä¿¡APIè·å |
| | | this.handleWxWorkLogin(); |
| | | return; |
| | | } |
| | | |
| | | // è°ç¨å端æ¥å£è¿è¡å
ç» |
| | | const response = await qyWechatAutoLogin(code); |
| | | |
| | | if (response.code === 200) { |
| | | // å
ç»æåï¼ä¿åtoken |
| | | const token = response.data.token; |
| | | |
| | | this.$store.commit('SET_TOKEN', token) |
| | | // å¿
é¡»è°ç¨setTokenä¿åå°æ¬å°åå¨ |
| | | const { setToken } = require('@/utils/auth') |
| | | setToken(token) |
| | | // è·åç¨æ·ä¿¡æ¯ |
| | | await this.$store.dispatch("GetInfo"); |
| | | |
| | | // 跳转å°é¦é¡µæå
¶ä»æå®é¡µé¢ |
| | | this.redirectAfterLogin(); |
| | | } else { |
| | | throw new Error(response.msg || "å
ç»å¤±è´¥"); |
| | | } |
| | | // #endif |
| | | |
| | | // #ifdef H5 |
| | | // æ£æ¥æ¯å¦å¨ä¼ä¸å¾®ä¿¡ç¯å¢ä¸ |
| | | if (!this.isWxWorkEnvironment()) { |
| | | throw new Error("请å¨ä¼ä¸å¾®ä¿¡å®¢æ·ç«¯ä¸æå¼"); |
| | | } |
| | | |
| | | // è·åURLåæ°ä¸çcode |
| | | const codeH5 = this.getUrlParam("code"); |
| | | |
| | | if (!codeH5) { |
| | | // å¦ææ²¡æcodeï¼å跳转å°ä¼ä¸å¾®ä¿¡ææé¡µé¢ |
| | | this.redirectToWxWorkAuth(); |
| | | return; |
| | | } |
| | | |
| | | // è°ç¨å端æ¥å£è¿è¡å
ç» |
| | | const responseH5 = await qyWechatAutoLogin(codeH5); |
| | | |
| | | if (responseH5.code === 200) { |
| | | // å
ç»æåï¼ä¿åtoken |
| | | const token = responseH5.data.token; |
| | | this.$store.commit("SET_TOKEN", token); |
| | | uni.setStorageSync("token", token); |
| | | |
| | | // è·åç¨æ·ä¿¡æ¯ |
| | | await this.$store.dispatch("GetInfo"); |
| | | |
| | | // 跳转å°é¦é¡µæå
¶ä»æå®é¡µé¢ |
| | | this.redirectAfterLogin(); |
| | | } else { |
| | | throw new Error(responseH5.msg || "å
ç»å¤±è´¥"); |
| | | } |
| | | // #endif |
| | | |
| | | // #ifndef MP-WEIXIN || H5 |
| | | throw new Error("该åè½ä»
æ¯æå¨ä¼ä¸å¾®ä¿¡ä¸ä½¿ç¨"); |
| | | // #endif |
| | | } catch (err) { |
| | | console.error("ä¼ä¸å¾®ä¿¡å
ç»å¤±è´¥:", err); |
| | | this.loading = false; |
| | | this.error = true; |
| | | this.errorMessage = err.message || "å
ç»å¤±è´¥ï¼è¯·ç¨åéè¯"; |
| | | } |
| | | }, |
| | | |
| | | /** |
| | | * å¤çä¼ä¸å¾®ä¿¡ç»å½ |
| | | */ |
| | | handleWxWorkLogin() { |
| | | // #ifdef MP-WEIXIN |
| | | // å¨ä¼ä¸å¾®ä¿¡å°ç¨åºä¸ï¼å¯ä»¥ç´æ¥è°ç¨ä¼ä¸å¾®ä¿¡ç»å½API |
| | | uni.login({ |
| | | provider: "weixin", |
| | | success: (loginRes) => { |
| | | console.log("ä¼ä¸å¾®ä¿¡ç»å½æå", loginRes); |
| | | // è°ç¨å端æ¥å£è¿è¡å
ç» |
| | | qyWechatAutoLogin(loginRes.code) |
| | | .then((response) => { |
| | | if (response.code === 200) { |
| | | // å
ç»æåï¼ä¿åtoken |
| | | const token = response.data.token; |
| | | this.$store.commit("SET_TOKEN", token); |
| | | uni.setStorageSync("token", token); |
| | | |
| | | // è·åç¨æ·ä¿¡æ¯ |
| | | this.$store.dispatch("GetInfo").then(() => { |
| | | // 跳转å°é¦é¡µæå
¶ä»æå®é¡µé¢ |
| | | this.redirectAfterLogin(); |
| | | }); |
| | | } else { |
| | | throw new Error(response.msg || "å
ç»å¤±è´¥"); |
| | | } |
| | | }) |
| | | .catch((error) => { |
| | | console.error("å
ç»å¤±è´¥:", error); |
| | | this.loading = false; |
| | | this.error = true; |
| | | this.errorMessage = error.message || "å
ç»å¤±è´¥ï¼è¯·ç¨åéè¯"; |
| | | }); |
| | | }, |
| | | fail: (err) => { |
| | | console.error("ä¼ä¸å¾®ä¿¡ç»å½å¤±è´¥:", err); |
| | | this.loading = false; |
| | | this.error = true; |
| | | this.errorMessage = "ä¼ä¸å¾®ä¿¡ç»å½å¤±è´¥ï¼è¯·ç¨åéè¯"; |
| | | }, |
| | | }); |
| | | // #endif |
| | | }, |
| | | |
| | | /** |
| | | * æ£æ¥æ¯å¦å¨ä¼ä¸å¾®ä¿¡ç¯å¢ |
| | | */ |
| | | isWxWorkEnvironment() { |
| | | const userAgent = navigator.userAgent.toLowerCase(); |
| | | return userAgent.includes("wxwork"); |
| | | }, |
| | | |
| | | /** |
| | | * è·åURLåæ° |
| | | */ |
| | | getUrlParam(name) { |
| | | // #ifdef H5 |
| | | const reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); |
| | | const r = window.location.search.substr(1).match(reg); |
| | | if (r != null) return decodeURIComponent(r[2]); |
| | | // #endif |
| | | |
| | | // #ifdef MP-WEIXIN |
| | | // å¨å°ç¨åºä¸å¯ä»¥éè¿å
¶ä»æ¹å¼è·ååæ° |
| | | // è¿éç®åå¤çï¼å®é
项ç®ä¸å¯ä»¥æ ¹æ®éè¦è°æ´ |
| | | // #endif |
| | | |
| | | return null; |
| | | }, |
| | | |
| | | /** |
| | | * 跳转å°ä¼ä¸å¾®ä¿¡ææé¡µé¢ |
| | | */ |
| | | redirectToWxWorkAuth() { |
| | | // ä»å
¨å±é
ç½®ä¸è·åä¼ä¸å¾®ä¿¡é
ç½® |
| | | const config = getApp().globalData.config; |
| | | const corpId = config.qyWechatCorpId || "your_corp_id"; // ä¼ä¸ID |
| | | const agentId = config.qyWechatAgentId || "your_agent_id"; // åºç¨ID |
| | | const redirectUri = encodeURIComponent(window.location.href); |
| | | const state = Date.now(); // é²éæ¾æ»å» |
| | | |
| | | const authUrl = `https://open.work.weixin.qq.com/wwopen/sso/qrConnect?appid=${corpId}&agentid=${agentId}&redirect_uri=${redirectUri}&state=${state}`; |
| | | |
| | | window.location.href = authUrl; |
| | | }, |
| | | |
| | | /** |
| | | * ç»å½æååç跳转å¤ç |
| | | */ |
| | | redirectAfterLogin() { |
| | | // æ£æ¥æ¯å¦æredirectåæ°æå®è·³è½¬é¡µé¢ |
| | | if (this.pageOptions.redirect) { |
| | | // è§£ç redirectåæ° |
| | | const redirectUrl = decodeURIComponent(this.pageOptions.redirect); |
| | | this.$tab.reLaunch(redirectUrl); |
| | | } else { |
| | | // é»è®¤è·³è½¬å°é¦é¡µ |
| | | this.$tab.reLaunch("/pages/index"); |
| | | } |
| | | }, |
| | | |
| | | /** |
| | | * éæ°å°è¯ç»å½ |
| | | */ |
| | | retryLogin() { |
| | | this.qyWechatAutoLogin(); |
| | | }, |
| | | }, |
| | | }; |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | | .container { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | justify-content: center; |
| | | min-height: 100vh; |
| | | padding: 40rpx; |
| | | background-color: #f8f8f8; |
| | | } |
| | | |
| | | .loading-content, |
| | | .error-content, |
| | | .success-content { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | justify-content: center; |
| | | text-align: center; |
| | | } |
| | | |
| | | .loading-icon, |
| | | .error-icon, |
| | | .success-icon { |
| | | width: 120rpx; |
| | | height: 120rpx; |
| | | margin-bottom: 30rpx; |
| | | } |
| | | |
| | | .loading-text, |
| | | .error-text, |
| | | .success-text { |
| | | font-size: 32rpx; |
| | | color: #333; |
| | | margin-bottom: 40rpx; |
| | | } |
| | | |
| | | .error-text, |
| | | .success-text { |
| | | font-weight: bold; |
| | | } |
| | | |
| | | .error-text { |
| | | color: #ff0000; |
| | | } |
| | | |
| | | .success-text { |
| | | color: #00cc00; |
| | | } |
| | | |
| | | .retry-btn { |
| | | width: 80%; |
| | | height: 80rpx; |
| | | background-color: #007aff; |
| | | color: #fff; |
| | | border-radius: 10rpx; |
| | | font-size: 32rpx; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | </style> |
| | |
| | | // 页é¢ç½åå |
| | | const whiteList = [ |
| | | '/pages/login', |
| | | '/pages/qylogin', // ä¼ä¸å¾®ä¿¡å
ç»é¡µé¢ï¼å¿å访é®ï¼ |
| | | '/pages/register', |
| | | '/pages/common/webview/index', |
| | | '/pages/mine/privacy-policy/index', // éç§æ¿çï¼å¿å访é®ï¼ |
| New file |
| | |
| | | package com.ruoyi.web.controller.system; |
| | | |
| | | import com.ruoyi.common.annotation.Anonymous; |
| | | import com.ruoyi.common.core.controller.BaseController; |
| | | import com.ruoyi.common.core.domain.AjaxResult; |
| | | import com.ruoyi.common.core.domain.entity.SysUser; |
| | | import com.ruoyi.framework.web.service.QyWechatLoginService; |
| | | import com.ruoyi.system.service.IQyWechatAccessTokenService; |
| | | import com.ruoyi.system.service.IQyWechatService; |
| | | import com.ruoyi.system.service.ISysConfigService; |
| | | import com.ruoyi.system.service.ISysUserService; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | |
| | | import com.alibaba.fastjson2.JSON; |
| | | import com.alibaba.fastjson2.JSONObject; |
| | | |
| | | /** |
| | | * ä¼ä¸å¾®ä¿¡å
ç»æ§å¶å¨ |
| | | * |
| | | * @author ruoyi |
| | | * @date 2025-12-14 |
| | | */ |
| | | @RestController |
| | | @RequestMapping("/system/qywechat") |
| | | public class QyWechatLoginController extends BaseController { |
| | | |
| | | private static final Logger log = LoggerFactory.getLogger(QyWechatLoginController.class); |
| | | |
| | | @Autowired |
| | | private IQyWechatAccessTokenService qyWechatAccessTokenService; |
| | | |
| | | @Autowired |
| | | private IQyWechatService qyWechatService; |
| | | |
| | | @Autowired |
| | | private ISysConfigService configService; |
| | | |
| | | @Autowired |
| | | private ISysUserService userService; |
| | | |
| | | @Autowired |
| | | private QyWechatLoginService qyWechatLoginService; |
| | | |
| | | /** |
| | | * ä¼ä¸å¾®ä¿¡å
ç»æ¥å£ |
| | | * |
| | | * @param params ä¼ä¸å¾®ä¿¡ææcode |
| | | * @return ç»å½ç»æ |
| | | */ |
| | | @Anonymous |
| | | @PostMapping("/autoLogin") |
| | | public AjaxResult autoLogin(@RequestBody Map<String, String> params) { |
| | | try { |
| | | String code = params.get("code"); |
| | | |
| | | if (code == null || code.isEmpty()) { |
| | | return AjaxResult.error("ç¼ºå°ææcodeåæ°"); |
| | | } |
| | | |
| | | // è·åä¼ä¸å¾®ä¿¡é
ç½® |
| | | String corpId = configService.selectConfigByKey("qy_wechat.corp_id"); |
| | | // è·åä¼ä¸å¾®ä¿¡å°ç¨åºçsecretï¼ç¨äºè·åAccessTokenï¼ |
| | | String miniProgramSecret = configService.selectConfigByKey("qy_wechat.miniprogram_secret"); |
| | | |
| | | if (corpId == null || miniProgramSecret == null) { |
| | | return AjaxResult.error("ä¼ä¸å¾®ä¿¡é
ç½®ä¸å®æ´ï¼è¯·æ£æ¥corp_idåminiprogram_secreté
ç½®"); |
| | | } |
| | | |
| | | // è·åAccessTokenï¼ä½¿ç¨å°ç¨åºçsecretï¼ |
| | | String accessToken = qyWechatAccessTokenService.getQyMiniAccessToken(corpId, miniProgramSecret); |
| | | if (accessToken == null) { |
| | | return AjaxResult.error("è·åä¼ä¸å¾®ä¿¡AccessToken失败"); |
| | | } |
| | | |
| | | // éè¿codeè·åç¨æ·ä¿¡æ¯ |
| | | Map<String, Object> userInfo = getUserInfoByCode(accessToken, code); |
| | | if (!((Boolean) userInfo.get("success"))) { |
| | | return AjaxResult.error((String) userInfo.get("message")); |
| | | } |
| | | |
| | | // è·åç¨æ·ID |
| | | String userId = (String) userInfo.get("userid"); |
| | | |
| | | // æ ¹æ®ä¼ä¸å¾®ä¿¡ç¨æ·IDæ¥æ¾ç³»ç»ç¨æ· |
| | | SysUser sysUser = userService.selectUserByQyWechatUserId(userId); |
| | | if (sysUser == null) { |
| | | return AjaxResult.error("该ä¼ä¸å¾®ä¿¡è´¦å·æªç»å®ç³»ç»ç¨æ·"); |
| | | } |
| | | |
| | | // æ£æ¥ç¨æ·ç¶æ |
| | | if ("1".equals(sysUser.getStatus())) { |
| | | return AjaxResult.error("ç¨æ·å·²è¢«åç¨ï¼è¯·è系管çå"); |
| | | } |
| | | |
| | | if ("1".equals(sysUser.getDelFlag())) { |
| | | return AjaxResult.error("ç¨æ·å·²è¢«å é¤ï¼è¯·è系管çå"); |
| | | } |
| | | |
| | | // 使ç¨QyWechatLoginServiceçætoken |
| | | String token = qyWechatLoginService.loginByQyUserId(userId, corpId); |
| | | |
| | | // æé è¿åç»æ |
| | | Map<String, Object> result = new HashMap<>(); |
| | | result.put("token", token); |
| | | result.put("user", sysUser); |
| | | |
| | | return AjaxResult.success("ç»å½æå", result); |
| | | } catch (Exception e) { |
| | | log.error("ä¼ä¸å¾®ä¿¡å
ç»å¼å¸¸", e); |
| | | return AjaxResult.error("ç»å½å¼å¸¸ï¼" + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * æ ¹æ®codeè·åç¨æ·ä¿¡æ¯ |
| | | * |
| | | * @param accessToken AccessToken |
| | | * @param code ææcode |
| | | * @return ç¨æ·ä¿¡æ¯ |
| | | */ |
| | | private Map<String, Object> getUserInfoByCode(String accessToken, String code) { |
| | | try { |
| | | Map<String, Object> result = new HashMap<>(); |
| | | |
| | | // æé 请æ±URL - 使ç¨ä¼ä¸å¾®ä¿¡å°ç¨åºä¸ç¨æ¥å£ |
| | | String url = "https://qyapi.weixin.qq.com/cgi-bin/miniprogram/jscode2session?access_token=" + accessToken + "&js_code=" + code + "&grant_type=authorization_code"; |
| | | |
| | | // åéHTTP GETè¯·æ± |
| | | String response = sendHttpGetRequest(url); |
| | | if (response == null || response.isEmpty()) { |
| | | result.put("success", false); |
| | | result.put("message", "è·åç¨æ·ä¿¡æ¯å¤±è´¥ï¼ååºä¸ºç©º"); |
| | | return result; |
| | | } |
| | | |
| | | // 使ç¨FastJSONè§£æååº |
| | | JSONObject jsonResponse = JSON.parseObject(response); |
| | | |
| | | // æ£æ¥æ¯å¦æé误 |
| | | Integer errcode = jsonResponse.getInteger("errcode"); |
| | | if (errcode != null && errcode != 0) { |
| | | String errmsg = jsonResponse.getString("errmsg"); |
| | | result.put("success", false); |
| | | result.put("message", "è·åç¨æ·ä¿¡æ¯å¤±è´¥ï¼é误ç ï¼" + errcode + "ï¼é误信æ¯ï¼" + errmsg); |
| | | return result; |
| | | } |
| | | |
| | | // æ£æ¥æ¯å¦å
å«useridåæ®µ |
| | | String userId = jsonResponse.getString("userid"); |
| | | if (userId == null || userId.isEmpty()) { |
| | | result.put("success", false); |
| | | result.put("message", "è·åç¨æ·ä¿¡æ¯å¤±è´¥ï¼æªæ¾å°ç¨æ·ID"); |
| | | return result; |
| | | } |
| | | |
| | | result.put("success", true); |
| | | result.put("userid", userId); |
| | | result.put("corpid", jsonResponse.getString("corpid")); |
| | | result.put("session_key", jsonResponse.getString("session_key")); |
| | | |
| | | return result; |
| | | } catch (Exception e) { |
| | | log.error("è·åç¨æ·ä¿¡æ¯å¼å¸¸", e); |
| | | Map<String, Object> result = new HashMap<>(); |
| | | result.put("success", false); |
| | | result.put("message", "è·åç¨æ·ä¿¡æ¯å¼å¸¸ï¼" + e.getMessage()); |
| | | return result; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * åéHTTP GETè¯·æ± |
| | | * |
| | | * @param url 请æ±URL |
| | | * @return ååºå
容 |
| | | */ |
| | | private String sendHttpGetRequest(String url) { |
| | | try { |
| | | java.net.HttpURLConnection conn = (java.net.HttpURLConnection) new java.net.URL(url).openConnection(); |
| | | conn.setRequestMethod("GET"); |
| | | conn.setConnectTimeout(5000); |
| | | conn.setReadTimeout(5000); |
| | | |
| | | int responseCode = conn.getResponseCode(); |
| | | if (responseCode == 200) { |
| | | java.io.BufferedReader reader = new java.io.BufferedReader( |
| | | new java.io.InputStreamReader(conn.getInputStream(), "UTF-8")); |
| | | StringBuilder response = new StringBuilder(); |
| | | String line; |
| | | while ((line = reader.readLine()) != null) { |
| | | response.append(line); |
| | | } |
| | | reader.close(); |
| | | return response.toString(); |
| | | } else { |
| | | log.error("HTTP请æ±å¤±è´¥ï¼ååºç : {}", responseCode); |
| | | return null; |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("åéHTTP请æ±å¤±è´¥", e); |
| | | return null; |
| | | } |
| | | } |
| | | } |
| | |
| | | basename: i18n/messages |
| | | profiles: |
| | | # ç¯å¢ dev|test|prod |
| | | active: prod |
| | | active: dev |
| | | # æä»¶ä¸ä¼ |
| | | servlet: |
| | | multipart: |
| | |
| | | import com.ruoyi.framework.security.handle.AuthenticationEntryPointImpl; |
| | | import com.ruoyi.framework.security.handle.LogoutSuccessHandlerImpl; |
| | | import com.ruoyi.framework.security.WechatAuthenticationProvider; |
| | | import com.ruoyi.framework.security.QyWechatAuthenticationProvider; |
| | | import com.ruoyi.common.annotation.Anonymous; |
| | | import org.springframework.security.web.util.matcher.RequestMatcher; |
| | | import org.springframework.web.method.HandlerMethod; |
| | |
| | | private WechatAuthenticationProvider wechatAuthenticationProvider; |
| | | |
| | | /** |
| | | * ä¼ä¸å¾®ä¿¡è®¤è¯æä¾è
|
| | | */ |
| | | @Autowired |
| | | private QyWechatAuthenticationProvider qyWechatAuthenticationProvider; |
| | | |
| | | /** |
| | | * è·åæææ 注äº@AnonymousçURL |
| | | */ |
| | | private Set<String> getAnonymousUrls() { |
| | |
| | | |
| | | /** |
| | | * 身份éªè¯å®ç° |
| | | * æ¯æç¨æ·åå¯ç 认è¯åå¾®ä¿¡è®¤è¯ |
| | | * æ¯æç¨æ·åå¯ç 认è¯ã微信认è¯åä¼ä¸å¾®ä¿¡è®¤è¯ |
| | | */ |
| | | @Bean |
| | | public AuthenticationManager authenticationManager() |
| | |
| | | daoAuthenticationProvider.setPasswordEncoder(bCryptPasswordEncoder()); |
| | | |
| | | // è¿åProviderManager,æ¯æå¤ç§è®¤è¯æ¹å¼ |
| | | return new ProviderManager(daoAuthenticationProvider, wechatAuthenticationProvider); |
| | | return new ProviderManager(daoAuthenticationProvider, wechatAuthenticationProvider, qyWechatAuthenticationProvider); |
| | | } |
| | | |
| | | /** |
| New file |
| | |
| | | package com.ruoyi.framework.security; |
| | | |
| | | import com.ruoyi.common.core.domain.entity.SysUser; |
| | | import com.ruoyi.common.core.domain.model.LoginUser; |
| | | import com.ruoyi.common.utils.StringUtils; |
| | | import com.ruoyi.framework.web.service.SysPermissionService; |
| | | import com.ruoyi.system.service.ISysUserService; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.security.authentication.AuthenticationProvider; |
| | | import org.springframework.security.authentication.BadCredentialsException; |
| | | import org.springframework.security.core.Authentication; |
| | | import org.springframework.security.core.AuthenticationException; |
| | | import org.springframework.stereotype.Component; |
| | | import java.util.Set; |
| | | |
| | | /** |
| | | * ä¼ä¸å¾®ä¿¡ç»å½è®¤è¯æä¾è
|
| | | * 类似äºDaoAuthenticationProvider |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | @Component |
| | | public class QyWechatAuthenticationProvider implements AuthenticationProvider |
| | | { |
| | | @Autowired |
| | | private ISysUserService userService; |
| | | |
| | | @Autowired |
| | | private SysPermissionService permissionService; |
| | | |
| | | @Override |
| | | public Authentication authenticate(Authentication authentication) throws AuthenticationException |
| | | { |
| | | QyWechatAuthenticationToken qyWechatToken = (QyWechatAuthenticationToken) authentication; |
| | | |
| | | String qyUserId = (String) qyWechatToken.getPrincipal(); |
| | | String corpId = (String) qyWechatToken.getCredentials(); |
| | | //qywechat__qyUserId |
| | | //对qywechat__è¿è¡å¤çå¾å°qyUserId |
| | | qyUserId = StringUtils.substringAfter(qyUserId, "qywechat__"); |
| | | // æ ¹æ®ä¼ä¸å¾®ä¿¡ç¨æ·IDæ¥è¯¢ç¨æ· |
| | | SysUser user = userService.selectUserByQyWechatUserId(qyUserId); |
| | | |
| | | if (user == null) |
| | | { |
| | | throw new BadCredentialsException("该ä¼ä¸å¾®ä¿¡è´¦å·å°æªç»å®ç³»ç»ç¨æ·"); |
| | | } |
| | | |
| | | // æ£æ¥ç¨æ·ç¶æ |
| | | if ("1".equals(user.getStatus())) |
| | | { |
| | | throw new BadCredentialsException("ç¨æ·å·²è¢«åç¨ï¼è¯·è系管çå"); |
| | | } |
| | | |
| | | if ("1".equals(user.getDelFlag())) |
| | | { |
| | | throw new BadCredentialsException("ç¨æ·å·²è¢«å é¤ï¼è¯·è系管çå"); |
| | | } |
| | | |
| | | // è·åç¨æ·æé |
| | | Set<String> permissions = permissionService.getMenuPermission(user); |
| | | |
| | | // å建LoginUser对象 |
| | | LoginUser loginUser = new LoginUser(user.getUserId(), user.getDeptId(), user, permissions); |
| | | |
| | | // è¿å已认è¯çToken |
| | | return new QyWechatAuthenticationToken(loginUser, corpId, loginUser.getAuthorities()); |
| | | } |
| | | |
| | | @Override |
| | | public boolean supports(Class<?> authentication) |
| | | { |
| | | return QyWechatAuthenticationToken.class.isAssignableFrom(authentication); |
| | | } |
| | | } |
| New file |
| | |
| | | package com.ruoyi.framework.security; |
| | | |
| | | import org.springframework.security.authentication.AbstractAuthenticationToken; |
| | | import org.springframework.security.core.GrantedAuthority; |
| | | import java.util.Collection; |
| | | |
| | | /** |
| | | * ä¼ä¸å¾®ä¿¡ç»å½è®¤è¯Token |
| | | * 类似äºUsernamePasswordAuthenticationToken |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | public class QyWechatAuthenticationToken extends AbstractAuthenticationToken |
| | | { |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | /** |
| | | * 认è¯ä¸»ä½(ç»å½å为ä¼ä¸å¾®ä¿¡ç¨æ·ID,ç»å½å为LoginUser) |
| | | */ |
| | | private final Object principal; |
| | | |
| | | /** |
| | | * 认è¯åè¯(ä¼ä¸å¾®ä¿¡CorpID) |
| | | */ |
| | | private Object credentials; |
| | | |
| | | /** |
| | | * å建æªè®¤è¯çToken(ç»å½å) |
| | | * |
| | | * @param qyUserId ä¼ä¸å¾®ä¿¡ç¨æ·ID |
| | | * @param corpId ä¼ä¸å¾®ä¿¡CorpID |
| | | */ |
| | | public QyWechatAuthenticationToken(String qyUserId, String corpId) |
| | | { |
| | | super(null); |
| | | this.principal = qyUserId; |
| | | this.credentials = corpId; |
| | | setAuthenticated(false); |
| | | } |
| | | |
| | | /** |
| | | * å建已认è¯çToken(ç»å½å) |
| | | * |
| | | * @param principal ç»å½ç¨æ·ä¿¡æ¯ |
| | | * @param credentials åè¯ |
| | | * @param authorities æéå表 |
| | | */ |
| | | public QyWechatAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) |
| | | { |
| | | super(authorities); |
| | | this.principal = principal; |
| | | this.credentials = credentials; |
| | | super.setAuthenticated(true); |
| | | } |
| | | |
| | | @Override |
| | | public Object getCredentials() |
| | | { |
| | | return this.credentials; |
| | | } |
| | | |
| | | @Override |
| | | public Object getPrincipal() |
| | | { |
| | | return this.principal; |
| | | } |
| | | |
| | | @Override |
| | | public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException |
| | | { |
| | | if (isAuthenticated) |
| | | { |
| | | throw new IllegalArgumentException( |
| | | "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead"); |
| | | } |
| | | super.setAuthenticated(false); |
| | | } |
| | | |
| | | @Override |
| | | public void eraseCredentials() |
| | | { |
| | | super.eraseCredentials(); |
| | | credentials = null; |
| | | } |
| | | } |
| New file |
| | |
| | | package com.ruoyi.framework.web.service; |
| | | |
| | | import com.ruoyi.common.constant.Constants; |
| | | import com.ruoyi.common.core.domain.entity.SysUser; |
| | | import com.ruoyi.common.core.domain.model.LoginUser; |
| | | import com.ruoyi.framework.manager.AsyncManager; |
| | | import com.ruoyi.framework.manager.factory.AsyncFactory; |
| | | import com.ruoyi.framework.security.QyWechatAuthenticationToken; |
| | | import com.ruoyi.system.service.ISysUserService; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.security.authentication.AuthenticationManager; |
| | | import org.springframework.security.authentication.BadCredentialsException; |
| | | import org.springframework.security.core.Authentication; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | /** |
| | | * ä¼ä¸å¾®ä¿¡ç»å½æ ¡éªæ¹æ³ |
| | | * 类似äºSysLoginService |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | @Component |
| | | public class QyWechatLoginService |
| | | { |
| | | @Autowired |
| | | private TokenService tokenService; |
| | | |
| | | @Autowired |
| | | private AuthenticationManager authenticationManager; |
| | | |
| | | @Autowired |
| | | private SysLoginService sysLoginService; |
| | | |
| | | @Autowired |
| | | private ISysUserService userService; |
| | | |
| | | /** |
| | | * ä¼ä¸å¾®ä¿¡ç¨æ·IDç»å½éªè¯ |
| | | * |
| | | * @param qyUserId ä¼ä¸å¾®ä¿¡ç¨æ·ID |
| | | * @param corpId ä¼ä¸å¾®ä¿¡CorpID |
| | | * @return token |
| | | */ |
| | | public String loginByQyUserId(String qyUserId, String corpId) |
| | | { |
| | | try |
| | | { |
| | | qyUserId = "qywechat__"+qyUserId; |
| | | // å建ä¼ä¸å¾®ä¿¡è®¤è¯Token |
| | | QyWechatAuthenticationToken authenticationToken = new QyWechatAuthenticationToken(qyUserId, corpId); |
| | | |
| | | // 使ç¨AuthenticationManagerè¿è¡è®¤è¯ |
| | | Authentication authentication = authenticationManager.authenticate(authenticationToken); |
| | | |
| | | // è®¤è¯æå,è·åLoginUser |
| | | LoginUser loginUser = (LoginUser) authentication.getPrincipal(); |
| | | |
| | | // è®°å½ç»å½æåæ¥å¿ |
| | | AsyncManager.me().execute(AsyncFactory.recordLogininfor( |
| | | loginUser.getUsername(), |
| | | Constants.LOGIN_SUCCESS, |
| | | "ä¼ä¸å¾®ä¿¡ç¨æ·IDç»å½æå")); |
| | | |
| | | // è®°å½ç»å½ä¿¡æ¯(IPåæ¶é´) |
| | | sysLoginService.recordLoginInfo(loginUser.getUserId()); |
| | | |
| | | // çætoken |
| | | return tokenService.createToken(loginUser); |
| | | } |
| | | catch (BadCredentialsException e) |
| | | { |
| | | // è®°å½ç»å½å¤±è´¥æ¥å¿ |
| | | AsyncManager.me().execute(AsyncFactory.recordLogininfor( |
| | | qyUserId, |
| | | Constants.LOGIN_FAIL, |
| | | e.getMessage())); |
| | | throw e; |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | // è®°å½ç»å½å¤±è´¥æ¥å¿ |
| | | AsyncManager.me().execute(AsyncFactory.recordLogininfor( |
| | | qyUserId, |
| | | Constants.LOGIN_FAIL, |
| | | e.getMessage())); |
| | | throw new BadCredentialsException(e.getMessage()); |
| | | } |
| | | } |
| | | } |
| | |
| | | |
| | | // å°è¯å¤ææ¯ææºå·ãopenIdè¿æ¯ç¨æ·å |
| | | SysUser user = null; |
| | | |
| | | //qywechat__ |
| | | if (username.startsWith("qywechat__")) |
| | | { |
| | | //ä¼ä¸å¾®ä¿¡ç»å½ |
| | | //qywechat__qyUserId |
| | | String qyUserId =StringUtils.substringAfter(username, "qywechat__"); |
| | | user = userService.selectUserByQyWechatUserId(qyUserId); |
| | | } |
| | | // 夿æ¯å¦ä¸ºå¾®ä¿¡OpenIDï¼é常以"o"å¼å¤´ï¼28ä½åç¬¦ï¼ |
| | | if (username.startsWith("o") && username.length() == 28) |
| | | else if (username.startsWith("o") && username.length() == 28) |
| | | { |
| | | // 微信OpenIDç»å½ |
| | | log.info("å°è¯ä½¿ç¨å¾®ä¿¡OpenIDç»å½ï¼{}", username); |
| | |
| | | public SysUser selectUserByOpenId(@Param("openId") String openId); |
| | | |
| | | /** |
| | | * éè¿ä¼ä¸å¾®ä¿¡ç¨æ·IDæ¥è¯¢ç¨æ· |
| | | * |
| | | * @param qyWechatUserId ä¼ä¸å¾®ä¿¡ç¨æ·ID |
| | | * @return ç¨æ·å¯¹è±¡ä¿¡æ¯ |
| | | */ |
| | | public SysUser selectUserByQyWechatUserId(@Param("qyWechatUserId") String qyWechatUserId); |
| | | |
| | | /** |
| | | * æ ¹æ®åå
¬å¸IDå表æ¥è¯¢ç¨æ·ï¼å
å«åå
¬å¸åå
¶ææåé¨é¨çç¨æ·ï¼ |
| | | * |
| | | * @param branchDeptIds åå
¬å¸IDå表 |
| | |
| | | * è·åä¼ä¸å¾®ä¿¡åºç¨çAccessToken |
| | | * |
| | | * @param corpId ä¼ä¸ID |
| | | * @param corpSecret åºç¨å¯é¥ |
| | | * @param secret åºç¨å¯é¥æå°ç¨åºå¯é¥ |
| | | * @return AccessToken |
| | | */ |
| | | String getAppAccessToken(String corpId, String corpSecret); |
| | | String getAppAccessToken(String corpId, String secret); |
| | | |
| | | /** |
| | | * å·æ°ä¼ä¸å¾®ä¿¡åºç¨çAccessToken |
| | | * |
| | | * @param corpId ä¼ä¸ID |
| | | * @param corpSecret åºç¨å¯é¥ |
| | | * @param secret åºç¨å¯é¥æå°ç¨åºå¯é¥ |
| | | * @return æ°çAccessToken |
| | | */ |
| | | String refreshAppAccessToken(String corpId, String corpSecret); |
| | | String refreshAppAccessToken(String corpId, String secret); |
| | | |
| | | /** |
| | | * è·åä¼ä¸å¾®ä¿¡å°ç¨åºçAccessToken |
| | | * |
| | | * @param corpId ä¼ä¸ID |
| | | * @param corpSecret å°ç¨åºå¯é¥ |
| | | * @return AccessToken |
| | | */ |
| | | String getQyMiniAccessToken(String corpId, String corpSecret); |
| | | |
| | | /** |
| | | * æ£æ¥ä¼ä¸å¾®ä¿¡æå¡æ¯å¦å¯ç¨ |
| | |
| | | public SysUser selectUserByOpenId(String openId); |
| | | |
| | | /** |
| | | * éè¿ä¼ä¸å¾®ä¿¡ç¨æ·IDæ¥è¯¢ç¨æ· |
| | | * |
| | | * @param qyWechatUserId ä¼ä¸å¾®ä¿¡ç¨æ·ID |
| | | * @return ç¨æ·å¯¹è±¡ä¿¡æ¯ |
| | | */ |
| | | public SysUser selectUserByQyWechatUserId(String qyWechatUserId); |
| | | |
| | | /** |
| | | * æ ¹æ®oaUserIdæ¥è¯¢ç¨æ· |
| | | * |
| | | * @param oaUserId SQL Serverä¸çOAç¨æ·ID |
| | |
| | | * è·åä¼ä¸å¾®ä¿¡åºç¨çAccessToken |
| | | * |
| | | * @param corpId ä¼ä¸ID |
| | | * @param corpSecret åºç¨å¯é¥ |
| | | * @param secret åºç¨å¯é¥æå°ç¨åºå¯é¥ |
| | | * @return AccessToken |
| | | */ |
| | | @Override |
| | | public String getAppAccessToken(String corpId, String corpSecret) { |
| | | public String getAppAccessToken(String corpId, String secret) { |
| | | try { |
| | | // åæ°æ ¡éª |
| | | if (StringUtils.isEmpty(corpId) || StringUtils.isEmpty(corpSecret)) { |
| | | log.warn("ä¼ä¸å¾®ä¿¡é
ç½®åæ°ä¸å®æ´ï¼corpIdæcorpSecret为空"); |
| | | if (StringUtils.isEmpty(corpId) || StringUtils.isEmpty(secret)) { |
| | | log.warn("ä¼ä¸å¾®ä¿¡é
ç½®åæ°ä¸å®æ´ï¼corpIdæsecret为空"); |
| | | return null; |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | // Tokenä¸åå¨æå·²è¿æï¼å·æ°Token |
| | | return refreshAppAccessToken(corpId, corpSecret); |
| | | return refreshAppAccessToken(corpId, secret); |
| | | } catch (Exception e) { |
| | | log.error("è·åä¼ä¸å¾®ä¿¡AccessToken失败", e); |
| | | return null; |
| | |
| | | * å·æ°ä¼ä¸å¾®ä¿¡åºç¨çAccessToken |
| | | * |
| | | * @param corpId ä¼ä¸ID |
| | | * @param corpSecret åºç¨å¯é¥ |
| | | * @param secret åºç¨å¯é¥æå°ç¨åºå¯é¥ |
| | | * @return æ°çAccessToken |
| | | */ |
| | | @Override |
| | | public String refreshAppAccessToken(String corpId, String corpSecret) { |
| | | public String refreshAppAccessToken(String corpId, String secret) { |
| | | try { |
| | | log.info("å¼å§å·æ°ä¼ä¸å¾®ä¿¡AccessToken"); |
| | | |
| | | // æå»ºè¯·æ±URL |
| | | String url = GET_ACCESS_TOKEN_URL + "?corpid=" + corpId + "&corpsecret=" + corpSecret; |
| | | String url = GET_ACCESS_TOKEN_URL + "?corpid=" + corpId + "&corpsecret=" + secret; |
| | | |
| | | // åéHTTP请æ±è·åToken |
| | | String response = sendHttpGetRequest(url); |
| | |
| | | } |
| | | |
| | | /** |
| | | * è·åä¼ä¸å¾®ä¿¡å°ç¨åºçAccessToken |
| | | * |
| | | * @param corpId ä¼ä¸ID |
| | | * @param corpSecret å°ç¨åºå¯é¥ |
| | | * @return AccessToken |
| | | */ |
| | | @Override |
| | | public String getQyMiniAccessToken(String corpId, String corpSecret) { |
| | | try { |
| | | // åæ°æ ¡éª |
| | | if (StringUtils.isEmpty(corpId) || StringUtils.isEmpty(corpSecret)) { |
| | | log.warn("ä¼ä¸å¾®ä¿¡å°ç¨åºé
ç½®åæ°ä¸å®æ´ï¼corpIdæcorpSecret为空"); |
| | | return null; |
| | | } |
| | | |
| | | // æ£æ¥æå¡æ¯å¦å¯ç¨ |
| | | if (!isEnabled()) { |
| | | log.info("ä¼ä¸å¾®ä¿¡æå¡å·²ç¦ç¨ï¼æ æ³è·åå°ç¨åºAccessToken"); |
| | | return null; |
| | | } |
| | | |
| | | // æå»ºé
ç½®é®åï¼ä½¿ç¨ä¸åçé®å以åºåæ®éåºç¨åå°ç¨åºï¼ |
| | | String tokenKey = "qy_wechat.mini_access_token." + corpId; |
| | | String expiresKey = "qy_wechat.mini_access_token_expires." + corpId; |
| | | |
| | | // ä»é
ç½®ä¸è·åTokenåè¿ææ¶é´ |
| | | String accessToken = configService.selectConfigByKey(tokenKey); |
| | | String expiresStr = configService.selectConfigByKey(expiresKey); |
| | | |
| | | // æ£æ¥Tokenæ¯å¦åå¨ä¸æªè¿æ |
| | | if (StringUtils.isNotEmpty(accessToken) && StringUtils.isNotEmpty(expiresStr)) { |
| | | try { |
| | | long expiresTime = Long.parseLong(expiresStr); |
| | | long currentTime = System.currentTimeMillis(); |
| | | |
| | | // é¢ç60ç§å®å
¨è¾¹çï¼é¿å
临çç¹è¿æ |
| | | if (currentTime < expiresTime - 60000) { |
| | | log.debug("使ç¨ç¼åçä¼ä¸å¾®ä¿¡å°ç¨åºAccessTokenï¼å©ä½æææ¶é´: {}ç§", |
| | | (expiresTime - currentTime) / 1000); |
| | | return accessToken; |
| | | } else { |
| | | log.info("ä¼ä¸å¾®ä¿¡å°ç¨åºAccessTokenå·²è¿ææå³å°è¿æï¼éè¦å·æ°"); |
| | | } |
| | | } catch (NumberFormatException e) { |
| | | log.warn("è§£æä¼ä¸å¾®ä¿¡å°ç¨åºAccessTokenè¿ææ¶é´å¤±è´¥: {}", expiresStr); |
| | | } |
| | | } |
| | | |
| | | // Tokenä¸åå¨æå·²è¿æï¼å·æ°Token |
| | | return refreshQyMiniAccessToken(corpId, corpSecret); |
| | | } catch (Exception e) { |
| | | log.error("è·åä¼ä¸å¾®ä¿¡å°ç¨åºAccessToken失败", e); |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * å·æ°ä¼ä¸å¾®ä¿¡å°ç¨åºçAccessToken |
| | | * |
| | | * @param corpId ä¼ä¸ID |
| | | * @param corpSecret å°ç¨åºå¯é¥ |
| | | * @return æ°çAccessToken |
| | | */ |
| | | public String refreshQyMiniAccessToken(String corpId, String corpSecret) { |
| | | try { |
| | | log.info("å¼å§å·æ°ä¼ä¸å¾®ä¿¡å°ç¨åºAccessToken"); |
| | | |
| | | // æå»ºè¯·æ±URL |
| | | String url = GET_ACCESS_TOKEN_URL + "?corpid=" + corpId + "&corpsecret=" + corpSecret; |
| | | |
| | | // åéHTTP请æ±è·åToken |
| | | String response = sendHttpGetRequest(url); |
| | | |
| | | if (StringUtils.isEmpty(response)) { |
| | | log.error("è·åä¼ä¸å¾®ä¿¡å°ç¨åºAccessToken失败ï¼ååºä¸ºç©º"); |
| | | return null; |
| | | } |
| | | |
| | | // è§£æååº |
| | | QyWechatTokenResponse tokenResponse = parseTokenResponse(response); |
| | | |
| | | if (tokenResponse == null || StringUtils.isEmpty(tokenResponse.getAccessToken())) { |
| | | log.error("è§£æä¼ä¸å¾®ä¿¡å°ç¨åºAccessTokenååºå¤±è´¥: {}", response); |
| | | return null; |
| | | } |
| | | |
| | | // 计ç®è¿ææ¶é´ï¼å½åæ¶é´ + æææ - 60ç§å®å
¨è¾¹çï¼ |
| | | long expiresTime = System.currentTimeMillis() + (tokenResponse.getExpiresIn() * 1000L) - 60000L; |
| | | |
| | | // æå»ºé
ç½®é®åï¼ä½¿ç¨ä¸åçé®å以åºåæ®éåºç¨åå°ç¨åºï¼ |
| | | String tokenKey = "qy_wechat.mini_access_token." + corpId; |
| | | String expiresKey = "qy_wechat.mini_access_token_expires." + corpId; |
| | | |
| | | // ä¿åå°ç³»ç»é
置表 |
| | | configService.updateConfigValue(tokenKey, tokenResponse.getAccessToken()); |
| | | configService.updateConfigValue(expiresKey, String.valueOf(expiresTime)); |
| | | |
| | | log.info("ä¼ä¸å¾®ä¿¡å°ç¨åºAccessTokenå·æ°æåï¼æææ: {}ç§", tokenResponse.getExpiresIn()); |
| | | return tokenResponse.getAccessToken(); |
| | | } catch (Exception e) { |
| | | log.error("å·æ°ä¼ä¸å¾®ä¿¡å°ç¨åºAccessToken失败", e); |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * æ£æ¥ä¼ä¸å¾®ä¿¡æå¡æ¯å¦å¯ç¨ |
| | | * |
| | | * @return true-å¯ç¨ï¼false-ç¦ç¨ |
| | |
| | | } |
| | | |
| | | /** |
| | | * éè¿ä¼ä¸å¾®ä¿¡ç¨æ·IDæ¥è¯¢ç¨æ· |
| | | * |
| | | * @param qyWechatUserId ä¼ä¸å¾®ä¿¡ç¨æ·ID |
| | | * @return ç¨æ·å¯¹è±¡ä¿¡æ¯ |
| | | */ |
| | | @Override |
| | | public SysUser selectUserByQyWechatUserId(String qyWechatUserId) |
| | | { |
| | | return userMapper.selectUserByQyWechatUserId(qyWechatUserId); |
| | | } |
| | | |
| | | /** |
| | | * æ ¹æ®oaUserIdæ¥è¯¢ç¨æ· |
| | | * |
| | | * @param oaUserId SQL Serverä¸çOAç¨æ·ID |
| | |
| | | where u.open_id = #{openId} and u.del_flag = '0' |
| | | </select> |
| | | |
| | | <!-- éè¿ä¼ä¸å¾®ä¿¡ç¨æ·IDæ¥è¯¢ç¨æ· --> |
| | | <select id="selectUserByQyWechatUserId" parameterType="String" resultMap="SysUserResult"> |
| | | <include refid="selectUserVo"/> |
| | | where u.qy_wechat_user_id = #{qyWechatUserId} and u.del_flag = '0' |
| | | </select> |
| | | |
| | | <!-- æ ¹æ®åå
¬å¸IDå表æ¥è¯¢ç¨æ·ï¼å
å«åå
¬å¸åå
¶ææåé¨é¨çç¨æ·ï¼ --> |
| | | <select id="selectUsersByBranchDeptIds" resultMap="SysUserResult"> |
| | | SELECT DISTINCT |
| | |
| | | |
| | | /* Layout */ |
| | | import Layout from '@/layout' |
| | | import qywechatRouter from './modules/qywechat' |
| | | |
| | | /** |
| | | * Note: è·¯ç±é
置项 |
| | |
| | | |
| | | // å¨æè·¯ç±ï¼åºäºç¨æ·æé卿å»å è½½ |
| | | export const dynamicRoutes = [ |
| | | qywechatRouter, |
| | | { |
| | | path: '/system/user-auth', |
| | | component: Layout, |
| New file |
| | |
| | | import Layout from '@/layout' |
| | | |
| | | const qywechatRouter = { |
| | | path: '/qywechat', |
| | | component: Layout, |
| | | redirect: 'noRedirect', |
| | | name: 'QyWechat', |
| | | meta: { title: 'ä¼ä¸å¾®ä¿¡', icon: 'wechat' }, |
| | | children: [ |
| | | { |
| | | path: 'test', |
| | | component: () => import('@/views/system/qywechat/test'), |
| | | name: 'QyWechatTest', |
| | | meta: { title: 'åè½æµè¯', icon: 'guide' } |
| | | }, |
| | | { |
| | | path: 'autologin', |
| | | component: () => import('@/views/system/qywechat/autologin'), |
| | | name: 'QyWechatAutoLogin', |
| | | meta: { title: 'å
ç»æµè¯', icon: 'lock' } |
| | | } |
| | | ] |
| | | } |
| | | |
| | | export default qywechatRouter |
| New file |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <el-card class="box-card"> |
| | | <div slot="header" class="clearfix"> |
| | | <span>ä¼ä¸å¾®ä¿¡å
ç»æµè¯</span> |
| | | </div> |
| | | |
| | | <el-alert |
| | | title="说æ" |
| | | type="info" |
| | | description="æ¤é¡µé¢ç¨äºæµè¯ä¼ä¸å¾®ä¿¡å
ç»åè½ï¼è¯·ç¡®ä¿å·²å¨ä¼ä¸å¾®ä¿¡ä¸é
置好ç¸å
³åæ°" |
| | | show-icon |
| | | :closable="false" |
| | | style="margin-bottom: 20px;" |
| | | > |
| | | </el-alert> |
| | | |
| | | <el-form ref="form" :model="form" :rules="rules" label-width="120px"> |
| | | <el-form-item label="ææCode" prop="code"> |
| | | <el-input v-model="form.code" placeholder="请è¾å
¥ä¼ä¸å¾®ä¿¡ææCode" /> |
| | | <div class="form-tip">å¯éè¿ä¼ä¸å¾®ä¿¡æ«ç ç»å½è·åCode</div> |
| | | </el-form-item> |
| | | |
| | | <el-form-item> |
| | | <el-button type="primary" @click="handleAutoLogin">æµè¯å
ç»</el-button> |
| | | <el-button @click="handleReset">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | |
| | | <el-divider /> |
| | | |
| | | <div v-if="loginResult"> |
| | | <h4>æµè¯ç»æï¼</h4> |
| | | <el-card class="result-card"> |
| | | <pre>{{ loginResult }}</pre> |
| | | </el-card> |
| | | </div> |
| | | </el-card> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import { getCodeImg } from "@/api/login"; |
| | | |
| | | export default { |
| | | name: "QyWechatAutoLogin", |
| | | data() { |
| | | return { |
| | | form: { |
| | | code: "" |
| | | }, |
| | | rules: { |
| | | code: [ |
| | | { required: true, message: "请è¾å
¥ææCode", trigger: "blur" } |
| | | ] |
| | | }, |
| | | loginResult: null |
| | | }; |
| | | }, |
| | | methods: { |
| | | /** æµè¯å
ç» */ |
| | | handleAutoLogin() { |
| | | this.$refs["form"].validate(valid => { |
| | | if (valid) { |
| | | // è°ç¨ä¼ä¸å¾®ä¿¡å
ç»æ¥å£ |
| | | this.$axios |
| | | .post("/system/qywechat/autoLogin", { code: this.form.code }) |
| | | .then(response => { |
| | | this.loginResult = response; |
| | | if (response.code === 200) { |
| | | this.$modal.msgSuccess("å
ç»æå"); |
| | | } else { |
| | | this.$modal.msgError(response.msg || "å
ç»å¤±è´¥"); |
| | | } |
| | | }) |
| | | .catch(error => { |
| | | this.loginResult = error; |
| | | this.$modal.msgError("请æ±å¼å¸¸ï¼" + error.message); |
| | | }); |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | /** é置表å */ |
| | | handleReset() { |
| | | this.$refs["form"].resetFields(); |
| | | this.loginResult = null; |
| | | } |
| | | } |
| | | }; |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | | .form-tip { |
| | | font-size: 12px; |
| | | color: #999; |
| | | margin-top: 5px; |
| | | } |
| | | |
| | | .result-card { |
| | | background-color: #f5f5f5; |
| | | pre { |
| | | white-space: pre-wrap; |
| | | word-wrap: break-word; |
| | | margin: 0; |
| | | } |
| | | } |
| | | </style> |
| New file |
| | |
| | | # ä¼ä¸å¾®ä¿¡å
ç»åè½ä½¿ç¨è¯´æ |
| | | |
| | | ## åè½æ¦è¿° |
| | | |
| | | ä¼ä¸å¾®ä¿¡å
ç»åè½å
è®¸ç¨æ·éè¿ä¼ä¸å¾®ä¿¡å®¢æ·ç«¯ç´æ¥ç»å½ç³»ç»ï¼æ éè¾å
¥ç¨æ·ååå¯ç ï¼æåç¨æ·ä½éªã |
| | | |
| | | ## å®ç°åç |
| | | |
| | | 1. ç¨æ·å¨ä¼ä¸å¾®ä¿¡å®¢æ·ç«¯ä¸è®¿é®ç³»ç»URL |
| | | 2. ç³»ç»æ£æµå°ä¼ä¸å¾®ä¿¡ç¯å¢ï¼èªå¨è·³è½¬å°ä¼ä¸å¾®ä¿¡ææé¡µé¢ |
| | | 3. ç¨æ·ç¡®è®¤ææåï¼ä¼ä¸å¾®ä¿¡è¿åææcode |
| | | 4. ç³»ç»éè¿codeè·åç¨æ·ä¿¡æ¯å¹¶å®æç»å½ |
| | | |
| | | ## æä»¶ç»æ |
| | | |
| | | ``` |
| | | åç«¯ï¼ |
| | | - app/pages/qylogin.vue # ç§»å¨ç«¯å
ç»é¡µé¢ |
| | | - ruoyi-ui/src/views/system/qywechat/autologin.vue # PC端å
ç»æµè¯é¡µé¢ |
| | | - ruoyi-ui/src/router/modules/qywechat.js # è·¯ç±é
ç½® |
| | | |
| | | åç«¯ï¼ |
| | | - ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/QyWechatLoginController.java # å
ç»æ§å¶å¨ |
| | | - ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java # ç¨æ·Mapperæ¥å£ |
| | | - ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml # ç¨æ·Mapper XML |
| | | - ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java # ç¨æ·æå¡æ¥å£ |
| | | - ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java # ç¨æ·æå¡å®ç° |
| | | ``` |
| | | |
| | | ## é
ç½®è¦æ± |
| | | |
| | | ### 1. ä¼ä¸å¾®ä¿¡é
ç½® |
| | | |
| | | å¨ç³»ç»é
ç½®ä¸æ·»å 以ä¸é
ç½®é¡¹ï¼ |
| | | |
| | | ```sql |
| | | -- ä¼ä¸å¾®ä¿¡å¯ç¨å¼å
³ |
| | | INSERT INTO sys_config VALUES (NULL, 'ä¼ä¸å¾®ä¿¡å¯ç¨å¼å
³', 'qy_wechat.enable', 'true', 'Y', 'ç³»ç»å
ç½®', 'æ¯å¦å¯ç¨ä¼ä¸å¾®ä¿¡åè½', '1', '1', '2025-12-14 10:00:00', 'admin', '2025-12-14 10:00:00', 'admin', NULL); |
| | | |
| | | -- ä¼ä¸å¾®ä¿¡CorpID |
| | | INSERT INTO sys_config VALUES (NULL, 'ä¼ä¸å¾®ä¿¡CorpID', 'qy_wechat.corp_id', 'your_corp_id', 'Y', 'ç³»ç»å
ç½®', 'ä¼ä¸å¾®ä¿¡ä¼ä¸ID', '1', '1', '2025-12-14 10:00:00', 'admin', '2025-12-14 10:00:00', 'admin', NULL); |
| | | |
| | | -- ä¼ä¸å¾®ä¿¡åºç¨Secretï¼ç¨äºè·åç¨æ·ä¿¡æ¯ï¼ |
| | | INSERT INTO sys_config VALUES (NULL, 'ä¼ä¸å¾®ä¿¡åºç¨Secret', 'qy_wechat.corp_secret', 'your_corp_secret', 'Y', 'ç³»ç»å
ç½®', 'ä¼ä¸å¾®ä¿¡åºç¨å¯é¥', '1', '1', '2025-12-14 10:00:00', 'admin', '2025-12-14 10:00:00', 'admin', NULL); |
| | | |
| | | -- ä¼ä¸å¾®ä¿¡å°ç¨åºSecretï¼ç¨äºè·åAccessTokenï¼ |
| | | INSERT INTO sys_config VALUES (NULL, 'ä¼ä¸å¾®ä¿¡å°ç¨åºSecret', 'qy_wechat.miniprogram_secret', 'your_miniprogram_secret', 'Y', 'ç³»ç»å
ç½®', 'ä¼ä¸å¾®ä¿¡å
³èå°ç¨åºå¯é¥', '1', '1', '2025-12-14 10:00:00', 'admin', '2025-12-14 10:00:00', 'admin', NULL); |
| | | |
| | | -- ä¼ä¸å¾®ä¿¡AgentId |
| | | INSERT INTO sys_config VALUES (NULL, 'ä¼ä¸å¾®ä¿¡AgentId', 'qy_wechat.agent_id', 'your_agent_id', 'Y', 'ç³»ç»å
ç½®', 'ä¼ä¸å¾®ä¿¡åºç¨ID', '1', '1', '2025-12-14 10:00:00', 'admin', '2025-12-14 10:00:00', 'admin', NULL); |
| | | ``` |
| | | |
| | | ### 2. ç¨æ·ç»å® |
| | | |
| | | éè¦å°ç³»ç»ç¨æ·ä¸ä¼ä¸å¾®ä¿¡ç¨æ·è¿è¡ç»å®ï¼å¨`sys_user`表ä¸è®¾ç½®`qy_wechat_user_id`åæ®µã |
| | | |
| | | ## ä½¿ç¨æµç¨ |
| | | |
| | | ### ç§»å¨ç«¯ä½¿ç¨ |
| | | |
| | | 1. ç¨æ·å¨ä¼ä¸å¾®ä¿¡ä¸æå¼ç³»ç»URL |
| | | 2. ç³»ç»èªå¨è·³è½¬å°å
ç»é¡µé¢ `/pages/qylogin` |
| | | 3. 页颿£æµä¼ä¸å¾®ä¿¡ç¯å¢å¹¶è·åææcode |
| | | 4. è°ç¨å端å
ç»æ¥å£å®æç»å½ |
| | | |
| | | ### PC端æµè¯ |
| | | |
| | | 1. ç»å½ç³»ç»åå° |
| | | 2. è¿å
¥ãä¼ä¸å¾®ä¿¡ã->ãå
ç»æµè¯ãèå |
| | | 3. è¾å
¥ä¼ä¸å¾®ä¿¡ææcodeè¿è¡æµè¯ |
| | | |
| | | ## æ¥å£è¯´æ |
| | | |
| | | ### å
ç»æ¥å£ |
| | | |
| | | ``` |
| | | POST /system/qywechat/autoLogin |
| | | |
| | | 请æ±åæ°ï¼ |
| | | { |
| | | "code": "ä¼ä¸å¾®ä¿¡ææcode" |
| | | } |
| | | |
| | | ååºç»æï¼ |
| | | { |
| | | "code": 200, |
| | | "msg": "ç»å½æå", |
| | | "data": { |
| | | "token": "ç»å½ä»¤ç", |
| | | "user": { |
| | | // ç¨æ·ä¿¡æ¯ |
| | | } |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | ## 注æäºé¡¹ |
| | | |
| | | 1. ä¼ä¸å¾®ä¿¡å
ç»åè½ä»
æ¯æå¨ä¼ä¸å¾®ä¿¡å®¢æ·ç«¯ä¸ä½¿ç¨ |
| | | 2. éè¦æ£ç¡®é
ç½®ä¼ä¸å¾®ä¿¡åºç¨çå¯ä¿¡åå |
| | | 3. ç¨æ·å¿
é¡»å
ç»å®ä¼ä¸å¾®ä¿¡è´¦å·æè½ä½¿ç¨å
ç»åè½ |
| | | 4. ç¡®ä¿æå¡å¨è½å¤è®¿é®ä¼ä¸å¾®ä¿¡APIæ¥å£ |
| | | |
| | | ## 常è§é®é¢ |
| | | |
| | | ### 1. ææå¤±è´¥ |
| | | |
| | | **é®é¢ç°è±¡**ï¼æç¤º"è·åç¨æ·ä¿¡æ¯å¤±è´¥" |
| | | |
| | | **è§£å³æ¹æ¡**ï¼ |
| | | - æ£æ¥ä¼ä¸å¾®ä¿¡é
ç½®æ¯å¦æ£ç¡® |
| | | - 确认åºç¨çå¯ä¿¡ååé
ç½® |
| | | - æ£æ¥ç½ç»æ¯å¦è½è®¿é®ä¼ä¸å¾®ä¿¡API |
| | | |
| | | ### 2. ç¨æ·æªç»å® |
| | | |
| | | **é®é¢ç°è±¡**ï¼æç¤º"该ä¼ä¸å¾®ä¿¡è´¦å·æªç»å®ç³»ç»ç¨æ·" |
| | | |
| | | **è§£å³æ¹æ¡**ï¼ |
| | | - å¨ç¨æ·ç®¡ç䏿¾å°å¯¹åºç¨æ· |
| | | - 设置`qy_wechat_user_id`åæ®µä¸ºä¼ä¸å¾®ä¿¡ç¨æ·ID |
| | | |
| | | ### 3. ç»å½å¼å¸¸ |
| | | |
| | | **é®é¢ç°è±¡**ï¼æç¤º"ç»å½å¼å¸¸" |
| | | |
| | | **è§£å³æ¹æ¡**ï¼ |
| | | - æ¥çç³»ç»æ¥å¿å®ä½å
·ä½é误 |
| | | - æ£æ¥ç¨æ·ç¶ææ¯å¦æ£å¸¸ |
| | | - 确认系ç»é
ç½®æ¯å¦å®æ´ |
| | | |
| | | ## æ©å±åè½ |
| | | |
| | | ### 1. èªå¨è·³è½¬é
ç½® |
| | | |
| | | å¯ä»¥å¨å端页é¢ä¸é
ç½®èªå¨è·³è½¬é»è¾ï¼ |
| | | |
| | | ```javascript |
| | | // æ£æ¥ä¼ä¸å¾®ä¿¡ç¯å¢ |
| | | isWxWorkEnvironment() { |
| | | const userAgent = navigator.userAgent.toLowerCase() |
| | | return userAgent.includes('wxwork') |
| | | } |
| | | ``` |
| | | |
| | | ### 2. ç¨æ·ç»å®æ¥å£ |
| | | |
| | | å¯ä»¥å¼åç¨æ·ç»å®ä¼ä¸å¾®ä¿¡çæ¥å£ï¼ |
| | | |
| | | ```java |
| | | @PostMapping("/bind") |
| | | public AjaxResult bindQyWechatUser(@RequestBody BindRequest request) { |
| | | // å®ç°ç¨æ·ç»å®é»è¾ |
| | | } |
| | | ``` |