背景
如上图,是我们各个业务系统进行SSO登录的流程,我们之前已经通过OIDC搭建之Ory Hydra 2.0实践,进行了登录流程的构建,那么本次我们进行一下登出流程的实践
首先我们的登出需求分为以下几种:
1、所有应用统一登出: 账号在 pc1:admin、wms
pc2:admin、pms
全部退出
2、单应用统一登出: 账号在 pc1:admin
pc2:admin
退出
3、单token登出: 账号在 pc1:admin
退出,pc2:admin
不退出 (仅支持业务系统实现)
最终取决于 this.hydraAdminService.revokeOAuth2ConsentSessions
的参数,具体实现如下
实现方式
业务系统 实现
在各个应用端添加退出接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| // 手工logout async logout(user) { const access_token = user.access_token const subject = user.mongo_id const client_id = user.app.client_id // 清除 login session const { data: revokeOAuth2LoginSessions } = await this.hydraAdminService.revokeOAuth2LoginSessions({ subject: subject }) console.log("revokeOAuth2LoginSessions", revokeOAuth2LoginSessions)
// 所有应用或单应用登出,清除 consent session 注销所有token // 通过client单应用登录后通过all全应用退出。 const { data: revokeOAuth2ConsentSessions } = await this.hydraAdminService.revokeOAuth2ConsentSessions({ subject: subject, client: client_id, all: false, }) console.log("revokeOAuth2ConsentSessions", revokeOAuth2ConsentSessions)
// 单token登出:只注销当前token // const headers = { 'Authorization': `Basic ${Buffer.from(`${this.config.get('app').client_id}:${this.config.get('app').client_secret}`).toString('base64')}` } // console.log("headers", headers) // const revokeOAuth2Token = await this.hydraPublicService.revokeOAuth2Token({ token: access_token }, { headers: headers }) // console.log("revokeOAuth2Token", revokeOAuth2Token) // return }
|
统一授权认证中心 实现
- 要求
登出链接:http://oauth2.dev.dakewe.com/oauth2/sessions/logout?id_token_hint=XXX
可选参数,id_token_hint其实是用来找到你对应的应用。建议都传
可选参数post_logout_redirect_uris,如需要退出后,返回业务系统。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| async getLogout(dto: GetLogoutDto) { const logout_challenge = dto.logout_challenge try { const { data: getLogoutRequest } = await this.hydraAdminService.getOAuth2LogoutRequest({ logoutChallenge: logout_challenge }) console.log('getLogoutRequest', getLogoutRequest) return getLogoutRequest } catch (error) { if (error.isAxiosError) { console.log(error.response) throw new HttpException(`${error.response.data.error},${error.response.data.error_description}`, error.response.status); } else { throw new HttpException(error, 500); } } }
async acceptLogout(acceptLogout: AcceptLogoutDto) { const { logout_challenge, is_all = false } = acceptLogout console.log("接受退出流程") let getOAuth2LogoutRequest try { const { data: data } = await this.hydraAdminService.getOAuth2LogoutRequest({ logoutChallenge: logout_challenge }) getOAuth2LogoutRequest = data } catch (error) { if (error.isAxiosError) { console.log(error.response) throw new HttpException(`${error.response.data.error},${error.response.data.error_description}`, error.response.status); } else { throw new HttpException(error, 500); } } console.log('getOAuth2LogoutRequest', getOAuth2LogoutRequest) try { const subject = getOAuth2LogoutRequest.subject const client = getOAuth2LogoutRequest.client console.log('-------client_id', client?.client_id) console.log('-------subject', subject) // 清楚 logout session const { data: acceptLogoutRequest } = await this.hydraAdminService.acceptOAuth2LogoutRequest({ logoutChallenge: logout_challenge }) console.log('acceptLogoutRequest', acceptLogoutRequest) // 清除 consent session 注销所有token const { data: revokeOAuth2ConsentSessions } = await this.hydraAdminService.revokeOAuth2ConsentSessions({ subject: subject, client: client && is_all === false ? client.client_id : undefined, all: is_all, }) console.log("revokeOAuth2ConsentSessions", revokeOAuth2ConsentSessions)
return acceptLogoutRequest.redirect_to } catch (error) { if (error.isAxiosError) { console.log(error.response) throw new HttpException(`${error.response.data.error},${error.response.data.error_description}`, error.response.status); } else { throw new HttpException(error, 500); } } }
|
相关链接
Implementing the OIDC logout endpoint & UI
Logout logic diagram