若依集成微软单点登录(SSO)

实现:单页面应用(SPA)登录时候选择SSO时候进行登录。

方案很多种,我选择前端登录页面选择SSO登录后到微软进行验证,异步回调后获取账号,使用账号结合默认密码调用原方法进行登录。该方案是局限了对应场景,但是实现很简单,只需要改造下若依的前端就行了。下面是流程图:

一、 前端登录页面login.vue

复制代码
到登录按钮组件下新增
<!-- 新增微软SSO登录按钮 -->
<el-button  type="text"  icon="el-icon-outer-link"  @click="msSsoLogin" style="margin-top: 10px; width: 100%;color:aliceblue;underline">微软SSO登录 </el-button>

二、 前端新增方法,我这里是调用后台获取链接,你也可直接前台拼接

javascript 复制代码
// 微软SSO登录:获取授权地址并跳转
msSsoLogin() {
    authorize().then(res => {
        const params = new URL(res.msg).searchParams;
        const obj = Object.fromEntries(params.entries());
        Cookies.set('nonce',obj.nonce); // 保存该信息后面解析token时候用
        window.location.href = res.msg;
    });
},

这是我后台拼接的方法

拼接完内容如下:

复制代码
 https://login.microsoftonline.com/*****0a9/oauth2/v2.0/authorize?client_id=*****e38f&response_type=id_token&redirect_uri=https%3A%2F%2F*****.com%2FssoCheck&nonce=194d09b387d848a79fd380eda2d4ac73&scope=openid profile&response_mode=fragment&domain_hint=*****t.com

三、前端拿到URL后直接转跳,转跳到前端新增的一个vue里,这时候就到微软那的验证了,填写完账号密码或者其他验证方式,验证成功后就会回调回来,下面是回调来我若依前端处理的方法,处理完后就直接拿着账号密码进行登录到该用户的界面下了。

javascript 复制代码
import Cookies from 'js-cookie'
  created() {
    let token = this.parseHash(this.$route.hash)
    console.log('回调token:',token);
    if(token.error){
        this.$message.error(token.error_description);
        this.$router.push({ path:  '/' })
        return
    }else{
        this.handleIdToken(token.id_token)
    }
  },
// 下面是method里的
  async handleIdToken(idToken) {
            const isValid = await this.validateIdToken(idToken);
            if (!isValid) {
                this.$message.error('身份令牌验证失败');
                this.$router.push('/login');
                return;
            }
        },
        parseIdTokenPayload(idToken) {
            try {
                const payloadBase64 = idToken.split('.')[1];
                const payloadJson = atob(payloadBase64.replace(/-/g, '+').replace(/_/g, '/'));
                console.log('payloadJson:', JSON.parse(payloadJson));
                return JSON.parse(payloadJson);
            } catch (error) {
                console.error('解析 id_token 失败:', error);
                return null;
            }
        },
        // 验证 id_token 方法
        async validateIdToken(idToken) {
            const payload = this.parseIdTokenPayload(idToken);
            if (!payload) return false;
            const errors = [];
            const expectedIss = 'https://login.microsoftonline.com/2***cdd0a9/v2.0';
            if (payload.iss !== expectedIss) errors.push('iss 不匹配');
            const expectedAud = '98e6****8f';
            if (payload.aud !== expectedAud) errors.push('aud 不匹配');
            const now = Math.floor(Date.now() / 1000);
            if (payload.exp < now) errors.push('token 已过期');
            if (payload.nonce !== Cookies.get('nonce')) errors.push('nonce 不匹配');
            if (errors.length > 0) {
                console.error('id_token 验证失败:', errors.join('; '));
                this.$message.error(`验证失败:${errors.join('; ')}`);
                return false;
            }
            console.log('id_token 验证成功:',payload);
            Cookies.set('email', payload.preferred_username)
            this.$store
                .dispatch('Login', {
                    username: payload.preferred_username.substring(0, payload.preferred_username.indexOf('@')),
                    password: '123456'
                })
                .then(() => {
                    this.$router
                        .push({ path: this.redirect || '/' })
                        .catch(() => {})
                })
            return true;
        },
        parseHash(hash){
            const clean = hash.slice(1)
           const params = new URLSearchParams(clean);
            return Object.fromEntries(params.entries())
        },

四、账号注销

javascript 复制代码
   async logout() {
      this.$confirm('确定注销并退出系统吗?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        this.$store.dispatch('LogOut').then(() => {
          const userEmail = Cookies.get('email');
          if(userEmail){
            const clientId = "98e683f9***10ae38f";
            const postLogoutRedirectUri = encodeURIComponent(window.location.origin + "/login");
            window.location.href = `https://login.microsoftonline.com/common/oauth2/v2.0/logout?client_id=${clientId}&post_logout_redirect_uri=${postLogoutRedirectUri}&logout_hint=${encodeURIComponent(userEmail)}`;;
          }else{
            this.$router.push("/login");
          }
        })
      }).catch(() => {});
    }

相关文档:

微软官方微软身份平台和 OAuth 2.0

相关推荐
灵感__idea21 小时前
Hello 算法:贪心的世界
前端·javascript·算法
killerbasd1 天前
牧苏苏传 我不装了 4/7
前端·javascript·vue.js
橘子编程1 天前
JavaScript与TypeScript终极指南
javascript·ubuntu·typescript
叫我一声阿雷吧1 天前
JS 入门通关手册(45):浏览器渲染原理与重绘重排(性能优化核心,面试必考
javascript·前端面试·前端性能优化·浏览器渲染·浏览器渲染原理,重排重绘·reflow·repaint
大家的林语冰1 天前
《前端周刊》尤大开源 Vite+ 全家桶,前端工业革命启动;尤大爆料 Void 云服务新产品,Vite 进军全栈开发;ECMA 源码映射规范......
前端·javascript·vue.js
jiayong231 天前
第 8 课:开始引入组合式函数
前端·javascript·学习
天若有情6731 天前
【C++原创开源】formort.h:一行头文件,实现比JS模板字符串更爽的链式拼接+响应式变量
开发语言·javascript·c++·git·github·开源项目·模版字符串
yuki_uix1 天前
重排、重绘与合成——浏览器渲染性能的底层逻辑
前端·javascript·面试
止观止1 天前
拥抱 ESNext:从 TC39 提案到生产环境中的现代 JS
开发语言·javascript·ecmascript·esnext
时寒的笔记1 天前
js逆向7_案例惠nong网
android·开发语言·javascript