From f4d875ae3c18e39b76bcc6f1c148fb010b20b101 Mon Sep 17 00:00:00 2001 From: xuyuxiang Date: Sun, 14 Sep 2025 00:20:56 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90=E6=9B=B4=E6=96=B0=E3=80=91=E5=BA=95?= =?UTF-8?q?=E5=BA=A7=E5=A2=9E=E5=8A=A0=E5=8A=A8=E6=80=81=E5=8F=A3=E4=BB=A4?= =?UTF-8?q?=E7=99=BB=E5=BD=95=EF=BC=8C=E5=AE=8C=E5=96=84=E5=8D=95=E7=82=B9?= =?UTF-8?q?=E7=99=BB=E5=BD=95=E5=AE=A2=E6=88=B7=E7=AB=AF=E7=94=A8=E4=BA=8E?= =?UTF-8?q?=E6=9C=AA=E6=9D=A5=E6=97=A0=E7=BC=9D=E6=8E=A5=E5=85=A5=E7=BB=9F?= =?UTF-8?q?=E4=B8=80=E8=AE=A4=E8=AF=81=E5=B9=B3=E5=8F=B0=EF=BC=8C=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E8=AF=B8=E5=A4=9A=E4=BB=A3=E7=A0=81=EF=BC=8C=E6=9B=B4?= =?UTF-8?q?=E6=96=B0sql?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 28 ++ snowy-admin-web/src/api/auth/loginApi.js | 8 + .../src/api/auth/{oauthApi.js => ssoApi.js} | 15 +- snowy-admin-web/src/api/auth/thirdApi.js | 4 + snowy-admin-web/src/api/sys/userCenterApi.js | 18 +- snowy-admin-web/src/locales/lang/en.js | 17 +- snowy-admin-web/src/locales/lang/zh-cn.js | 21 +- snowy-admin-web/src/router/systemRouter.js | 15 +- snowy-admin-web/src/router/whiteList.js | 5 +- .../src/views/auth/login/callback.vue | 188 ++++++-- .../src/views/auth/login/emailLoginForm.vue | 2 +- .../src/views/auth/login/login.vue | 78 ++-- .../src/views/auth/login/otpLoginForm.vue | 115 +++++ .../src/views/auth/login/phoneLoginForm.vue | 2 +- .../src/views/auth/login/threeLogin.vue | 19 +- .../src/views/auth/login/threeLoginForApp.vue | 66 +++ snowy-admin-web/src/views/auth/login/util.js | 48 +- snowy-admin-web/src/views/auth/sso/index.vue | 204 +++++++++ snowy-admin-web/src/views/biz/user/index.vue | 4 +- .../views/dev/config/loginConfig/bForm.vue | 12 +- .../views/dev/config/loginConfig/cForm.vue | 11 +- snowy-admin-web/src/views/sys/user/index.vue | 4 +- .../src/views/sys/user/userCenter.vue | 2 +- .../views/sys/user/userTab/accountBasic.vue | 6 +- .../views/sys/user/userTab/accountBind.vue | 56 ++- .../sys/user/userTab/bindForm/bindOtp.vue | 120 +++++ snowy-common/pom.xml | 18 + .../xiaonuo/common/prop/CommonProperties.java | 3 + .../xiaonuo/common/util/CommonOtpUtil.java | 144 ++++++ .../java/vip/xiaonuo/auth/api/AuthApi.java | 32 ++ .../vip/xiaonuo/client/ClientUserApi.java | 74 ++++ .../java/vip/xiaonuo/sys/api/SysUserApi.java | 8 + snowy-plugin/snowy-plugin-auth/pom.xml | 18 + .../auth/modular/auth/AuthApiProvider.java | 25 ++ .../controller/AuthClientController.java | 26 ++ .../login/controller/AuthController.java | 26 ++ .../login/param/AuthOtpLoginParam.java | 51 +++ .../modular/login/service/AuthService.java | 24 + .../login/service/impl/AuthServiceImpl.java | 409 +++++++++++++----- .../modular/sso/config/AuthSsoConfigure.java | 45 ++ .../sso/controller/AuthSsoController.java | 56 ++- .../sso/param/AuthGetSsoAuthUrlParam.java | 34 ++ .../modular/sso/service/AuthSsoService.java | 27 +- .../sso/service/impl/AuthSsoServiceImpl.java | 66 ++- .../third/controller/AuthThirdController.java | 18 +- .../param/AuthThirdBindAccountParam.java | 56 +++ .../third/param/AuthThirdRenderParam.java | 5 + .../third/service/AuthThirdService.java | 9 + .../service/impl/AuthThirdServiceImpl.java | 98 +++-- .../client/core/enums/ClientYesOrNoEnum.java | 37 ++ .../modular/user/entity/ClientUserExt.java | 7 + .../user/provider/ClientUserApiProvider.java | 85 ++++ .../user/service/ClientUserExtService.java | 2 +- .../user/service/ClientUserService.java | 9 + .../impl/ClientUserExtServiceImpl.java | 9 +- .../service/impl/ClientUserServiceImpl.java | 17 + .../service/impl/DevConfigServiceImpl.java | 10 +- .../sys/core/enums/SysYesOrNoEnum.java | 26 +- .../sys/modular/org/entity/SysOrgExt.java | 8 + .../controller/SysUserCenterController.java | 61 ++- .../sys/modular/user/entity/SysUserExt.java | 16 + .../modular/user/param/SysUserOtpParam.java | 34 ++ .../user/provider/SysUserApiProvider.java | 5 + .../user/result/SysUserOtpInfoResult.java | 74 ++++ .../user/service/SysUserExtService.java | 2 +- .../modular/user/service/SysUserService.java | 41 ++ .../service/impl/SysUserExtServiceImpl.java | 9 +- .../user/service/impl/SysUserServiceImpl.java | 84 ++++ .../xiaonuo/core/config/GlobalConfigure.java | 13 + .../src/main/resources/_sql/snowy_mysql.sql | 11 +- .../src/main/resources/application.properties | 8 +- 71 files changed, 2613 insertions(+), 295 deletions(-) rename snowy-admin-web/src/api/auth/{oauthApi.js => ssoApi.js} (77%) create mode 100644 snowy-admin-web/src/views/auth/login/otpLoginForm.vue create mode 100644 snowy-admin-web/src/views/auth/login/threeLoginForApp.vue create mode 100644 snowy-admin-web/src/views/auth/sso/index.vue create mode 100644 snowy-admin-web/src/views/sys/user/userTab/bindForm/bindOtp.vue create mode 100644 snowy-common/src/main/java/vip/xiaonuo/common/util/CommonOtpUtil.java create mode 100644 snowy-plugin-api/snowy-plugin-client-api/src/main/java/vip/xiaonuo/client/ClientUserApi.java create mode 100644 snowy-plugin/snowy-plugin-auth/src/main/java/vip/xiaonuo/auth/modular/login/param/AuthOtpLoginParam.java create mode 100644 snowy-plugin/snowy-plugin-auth/src/main/java/vip/xiaonuo/auth/modular/sso/config/AuthSsoConfigure.java create mode 100644 snowy-plugin/snowy-plugin-auth/src/main/java/vip/xiaonuo/auth/modular/sso/param/AuthGetSsoAuthUrlParam.java create mode 100644 snowy-plugin/snowy-plugin-auth/src/main/java/vip/xiaonuo/auth/modular/third/param/AuthThirdBindAccountParam.java create mode 100644 snowy-plugin/snowy-plugin-client/src/main/java/vip/xiaonuo/client/core/enums/ClientYesOrNoEnum.java create mode 100644 snowy-plugin/snowy-plugin-client/src/main/java/vip/xiaonuo/client/modular/user/provider/ClientUserApiProvider.java rename snowy-plugin-api/snowy-plugin-client-api/src/main/java/vip/xiaonuo/client/package-info.java => snowy-plugin/snowy-plugin-sys/src/main/java/vip/xiaonuo/sys/core/enums/SysYesOrNoEnum.java (69%) create mode 100644 snowy-plugin/snowy-plugin-sys/src/main/java/vip/xiaonuo/sys/modular/user/param/SysUserOtpParam.java create mode 100644 snowy-plugin/snowy-plugin-sys/src/main/java/vip/xiaonuo/sys/modular/user/result/SysUserOtpInfoResult.java diff --git a/pom.xml b/pom.xml index d1d2fe36..6ff7de3d 100644 --- a/pom.xml +++ b/pom.xml @@ -252,6 +252,27 @@ 0.16.4 + + + com.google.zxing + core + 3.5.3 + + + + + org.bouncycastle + bcprov-jdk15on + 1.70 + + + + + org.bouncycastle + bcpkix-jdk15on + 1.70 + + cn.dev33 @@ -287,6 +308,13 @@ 1.44.0 + + + cn.dev33 + sa-token-forest + 1.44.0 + + me.zhyd.oauth diff --git a/snowy-admin-web/src/api/auth/loginApi.js b/snowy-admin-web/src/api/auth/loginApi.js index 850f9ce0..24bcdbea 100644 --- a/snowy-admin-web/src/api/auth/loginApi.js +++ b/snowy-admin-web/src/api/auth/loginApi.js @@ -53,5 +53,13 @@ export default { // 注册用户 register(data) { return request('register', data) + }, + // B端动态口令登录 + loginByOtp(data) { + return request('doLoginByOtp', data, 'post', false) + }, + // B端判断是否登录 + isLogin(data) { + return request('isLogin', data, 'get') } } diff --git a/snowy-admin-web/src/api/auth/oauthApi.js b/snowy-admin-web/src/api/auth/ssoApi.js similarity index 77% rename from snowy-admin-web/src/api/auth/oauthApi.js rename to snowy-admin-web/src/api/auth/ssoApi.js index bb0c2198..cd32c2c2 100644 --- a/snowy-admin-web/src/api/auth/oauthApi.js +++ b/snowy-admin-web/src/api/auth/ssoApi.js @@ -10,7 +10,7 @@ */ import { baseRequest } from '@/utils/request' -const request = (url, ...arg) => baseRequest(`/auth/third/` + url, ...arg) +const request = (url, ...arg) => baseRequest(`/auth/sso/b/` + url, ...arg) /** * 三方登录 * @@ -18,12 +18,13 @@ const request = (url, ...arg) => baseRequest(`/auth/third/` + url, ...arg) * @date 2022-09-22 22:33:20 */ export default { - // 第三方登录页面渲染 - thirdRender(data) { - return request('render', data, 'get') + + // B端获取认证中心地址 + getSsoAuthUrl(data) { + return request('getSsoAuthUrl', data, 'get') }, - // 第三方登录授权回调 - thirdCallback(data) { - return request('callback', data, 'get') + // B端根据ticket执行单点登录 + doLoginByTicket(data) { + return request('doLoginByTicket', data) } } diff --git a/snowy-admin-web/src/api/auth/thirdApi.js b/snowy-admin-web/src/api/auth/thirdApi.js index 1a01c440..fa69de6f 100644 --- a/snowy-admin-web/src/api/auth/thirdApi.js +++ b/snowy-admin-web/src/api/auth/thirdApi.js @@ -29,5 +29,9 @@ export default { // 第三方登录授权回调 thirdCallback(data) { return request('callback', data, 'get') + }, + // 第三方登录绑定账号 + thirdBindAccount(data) { + return request('bindAccount', data) } } diff --git a/snowy-admin-web/src/api/sys/userCenterApi.js b/snowy-admin-web/src/api/sys/userCenterApi.js index 1dcd42a4..b763cac3 100644 --- a/snowy-admin-web/src/api/sys/userCenterApi.js +++ b/snowy-admin-web/src/api/sys/userCenterApi.js @@ -155,5 +155,21 @@ export default { // 获取修改密码验证方式及配置 userGetUpdatePasswordValidConfig(data) { return request('getUpdatePasswordValidConfig', data, 'get') - } + }, + // 获取动态口令绑定状态 + userCenterGetOtpInfoBindStatus(data) { + return request('getOtpInfoBindStatus', data, 'get') + }, + // 获取动态口令信息 + userCenterGetOtpInfo(data) { + return request('getOtpInfo', data, 'get') + }, + // 绑定动态口令 + userCenterBindOtp(data) { + return request('bindOtp', data) + }, + // 解绑动态口令 + userCenterUnBindOtp(data) { + return request('unBindOtp', data) + }, } diff --git a/snowy-admin-web/src/locales/lang/en.js b/snowy-admin-web/src/locales/lang/en.js index ec2e7b45..05623d83 100644 --- a/snowy-admin-web/src/locales/lang/en.js +++ b/snowy-admin-web/src/locales/lang/en.js @@ -38,11 +38,14 @@ export default { accountError: 'Please input a user account', PWPlaceholder: 'Please input a password', PWError: 'Please input a password', - validLaceholder: 'Please input a valid', + validPlaceholder: 'Please input a valid', validError: 'Please input a valid', accountPassword: 'Account Password', - phoneSms: 'Phone SMS', + phoneLogin: 'Phone Login', emailLogin: 'Email Login', + otpLogin: 'OTP Login', + thirdLogin: 'Third Login', + bindAccount: 'Bind Account', phonePlaceholder: 'Please input a phone', phoneInputNumberPlaceholder: 'Please input a phone 11-digit', smsCodePlaceholder: 'Please input a SMS code', @@ -56,6 +59,7 @@ export default { emailPlaceholder: 'Please input a correct email', emailCodePlaceholder: 'Please input a Email code', emailValidPlaceholder: 'Please input a email', + otpCodePlaceholder: 'Please input a OTP code', restPhoneType: 'For phone rest', restEmailType: 'For email rest', register: 'Register', @@ -63,7 +67,10 @@ export default { notAccountPleaseRegister: 'Not Account? Register!', haveAccountPleaseLogin: 'Have Account? Go Login!', enterAgainPassword: 'Please re-enter your password', - enteredPasswordsDiffer: 'Entered passwords differ' + enteredPasswordsDiffer: 'Entered passwords differ', + paramError: 'Param Error', + thirdLoginError: 'Third Login Error', + frontLogin: 'Front Login', }, user: { userStatus: 'User Status', @@ -76,7 +83,7 @@ export default { exportUserInfo: 'Export UserInfo', placeholderNameAndSearchKey: 'Please enter your name or keyword', placeholderUserStatus: 'Please select status', - popconfirmDeleteUser: 'Are you sure you want to delete it?', - popconfirmResatUserPwd: 'Are you sure you want to reset?' + popConfirmDeleteUser: 'Are you sure you want to delete it?', + popConfirmResatUserPwd: 'Are you sure you want to reset?' } } diff --git a/snowy-admin-web/src/locales/lang/zh-cn.js b/snowy-admin-web/src/locales/lang/zh-cn.js index ae67b01a..a1fe7e1f 100644 --- a/snowy-admin-web/src/locales/lang/zh-cn.js +++ b/snowy-admin-web/src/locales/lang/zh-cn.js @@ -40,11 +40,14 @@ export default { accountError: '请输入账号', PWPlaceholder: '请输入密码', PWError: '请输入密码', - validLaceholder: '请输入验证码', + validPlaceholder: '请输入验证码', validError: '请输入验证码', accountPassword: '账号密码', - phoneSms: '手机号登录', - emailLogin: '邮箱号登录', + phoneLogin: '手机号登录', + emailLogin: '邮箱登录', + otpLogin: '动态口令登录', + thirdLogin: '三方登录', + bindAccount: '绑定账号', phonePlaceholder: '请输入手机号', phoneInputNumberPlaceholder: '请输入11位手机号', smsCodePlaceholder: '请输入短信验证码', @@ -55,9 +58,10 @@ export default { newPwdPlaceholder: '请输入新密码', backLogin: '返回登录', restPassword: '重置密码', - emailPlaceholder: '请输入邮箱号', + emailPlaceholder: '请输入邮箱', emailCodePlaceholder: '请输入邮件验证码', emailValidPlaceholder: '请输入正确的邮箱号', + otpCodePlaceholder: '请输入动态口令', restPhoneType: '手机号找回', restEmailType: '邮箱找回', register: '注册', @@ -65,7 +69,10 @@ export default { notAccountPleaseRegister: '没有账号?前往注册!', haveAccountPleaseLogin: '已有账号?去登录!', enterAgainPassword: '请再次输入密码', - enteredPasswordsDiffer: '两次输入密码不一致' + enteredPasswordsDiffer: '两次输入密码不一致', + paramError: '参数错误', + thirdLoginError: '登录失败', + frontLogin: '前台登录', }, user: { userStatus: '用户状态', @@ -78,7 +85,7 @@ export default { exportUserInfo: '导出信息', placeholderNameAndSearchKey: '请输入姓名或关键词', placeholderUserStatus: '请选择状态', - popconfirmDeleteUser: '确定要删除吗?', - popconfirmResatUserPwd: '确定要重置吗?' + popConfirmDeleteUser: '确定要删除吗?', + popConfirmResatUserPwd: '确定要重置吗?' } } diff --git a/snowy-admin-web/src/router/systemRouter.js b/snowy-admin-web/src/router/systemRouter.js index 86f8620d..19072a62 100644 --- a/snowy-admin-web/src/router/systemRouter.js +++ b/snowy-admin-web/src/router/systemRouter.js @@ -13,11 +13,11 @@ import tool from '@/utils/tool' import routerUtil from '@/utils/routerUtil' const Layout = () => import('@/layout/index.vue') +const Sso = () => import('@/views/auth/sso/index.vue') const Login = () => import('@/views/auth/login/login.vue') const FindPwd = () => import('@/views/auth/findPwd/index.vue') const Callback = () => import('@/views/auth/login/callback.vue') const Register = () => import('@/views/auth/login/register.vue') - // 系统路由 const routes = [ { @@ -27,6 +27,13 @@ const routes = [ redirect: tool.data.get('MENU') ? routerUtil.getIndexMenu(tool.data.get('MENU')).path : config.DASHBOARD_URL, children: [] }, + { + path: '/sso', + component: Sso, + meta: { + title: '单点登录' + } + }, { path: '/login', component: Login, @@ -49,12 +56,12 @@ const routes = [ } }, { - path: '/callback', + path: '/callback/:platform', component: Callback, meta: { - title: '三方登录' + title: '三方登录回调' } - } + }, ] export default routes diff --git a/snowy-admin-web/src/router/whiteList.js b/snowy-admin-web/src/router/whiteList.js index f324358e..803ec426 100644 --- a/snowy-admin-web/src/router/whiteList.js +++ b/snowy-admin-web/src/router/whiteList.js @@ -9,6 +9,9 @@ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip */ const constRouters = [ + { + path: '/sso' + }, { path: '/findpwd' }, @@ -16,7 +19,7 @@ const constRouters = [ path: '/register' }, { - path: '/callback' + path: '/callback/:platform' }, { path: '/other', diff --git a/snowy-admin-web/src/views/auth/login/callback.vue b/snowy-admin-web/src/views/auth/login/callback.vue index fe274855..aa025aca 100644 --- a/snowy-admin-web/src/views/auth/login/callback.vue +++ b/snowy-admin-web/src/views/auth/login/callback.vue @@ -21,13 +21,68 @@ @@ -36,20 +91,53 @@ diff --git a/snowy-admin-web/src/views/auth/login/phoneLoginForm.vue b/snowy-admin-web/src/views/auth/login/phoneLoginForm.vue index 54bd4e62..c8a73822 100644 --- a/snowy-admin-web/src/views/auth/login/phoneLoginForm.vue +++ b/snowy-admin-web/src/views/auth/login/phoneLoginForm.vue @@ -51,7 +51,7 @@ + diff --git a/snowy-admin-web/src/views/auth/login/threeLoginForApp.vue b/snowy-admin-web/src/views/auth/login/threeLoginForApp.vue new file mode 100644 index 00000000..19e9eb30 --- /dev/null +++ b/snowy-admin-web/src/views/auth/login/threeLoginForApp.vue @@ -0,0 +1,66 @@ + + + + diff --git a/snowy-admin-web/src/views/auth/login/util.js b/snowy-admin-web/src/views/auth/login/util.js index 28b3b30c..937d4f1a 100644 --- a/snowy-admin-web/src/views/auth/login/util.js +++ b/snowy-admin-web/src/views/auth/login/util.js @@ -8,6 +8,7 @@ import { useMenuStore } from '@/store/menu' import { useUserStore } from '@/store/user' export const afterLogin = async (loginToken) => { + const route = router.currentRoute.value const menuStore = useMenuStore() tool.data.set('TOKEN', loginToken) // 初始化用户信息 @@ -20,7 +21,7 @@ export const afterLogin = async (loginToken) => { // 重置系统默认应用 tool.data.set('SNOWY_MENU_MODULE_ID', menu[0].id) - message.success('登录成功') + if (tool.data.get('LAST_VIEWS_PATH')) { // 如果有缓存,将其登录跳转到最后访问的路由 indexMenu = tool.data.get('LAST_VIEWS_PATH') @@ -44,13 +45,40 @@ export const afterLogin = async (loginToken) => { // 设置字典到store中 tool.data.set('DICT_TYPE_TREE_DATA', data) }) - await router.replace({ - path: indexMenu - }) - // 判断用户密码是否过期 - userCenterApi.userCenterIsUserPasswordExpired().then((expired) => { - if (expired) { - message.warning('当前登录密码已过期,请及时更改!') - } - }) + + // 此处判断是否存在跳转页面,如存在则跳转,否则走原来逻辑 + if(route.query.redirect_uri) { + // 跳转到回调页 + message.success('登录成功,即将跳转...') + setTimeout(function () { + window.location.href = route.query.redirect_uri; + }, 500); + } else if(route.query.redirect) { + // 跳转到回调页 + message.success('登录成功,即将跳转...') + setTimeout(function () { + window.location.href = route.query.redirect; + }, 500); + } else if(route.query.back) { + // 跳转到回调页 + message.success('登录成功,即将跳转...') + setTimeout(function () { + window.location.href = route.query.back; + }, 500); + } else { + message.success('登录成功,即将跳转...') + setTimeout(function () { + // 跳转到首页 + router.replace({ + path: indexMenu + }).then(() => { + // 判断用户密码是否过期 + userCenterApi.userCenterIsUserPasswordExpired().then((expired) => { + if (expired) { + message.warning('当前登录密码已过期,请及时更改!') + } + }) + }) + }, 500); + } } diff --git a/snowy-admin-web/src/views/auth/sso/index.vue b/snowy-admin-web/src/views/auth/sso/index.vue new file mode 100644 index 00000000..6d8c2d75 --- /dev/null +++ b/snowy-admin-web/src/views/auth/sso/index.vue @@ -0,0 +1,204 @@ + + + + + diff --git a/snowy-admin-web/src/views/biz/user/index.vue b/snowy-admin-web/src/views/biz/user/index.vue index 43106869..a28037a6 100644 --- a/snowy-admin-web/src/views/biz/user/index.vue +++ b/snowy-admin-web/src/views/biz/user/index.vue @@ -105,7 +105,7 @@