oauth2之hydra 2.1.0 登出机制实践

背景

4AxA4q

如上图,是我们各个业务系统进行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
}

统一授权认证中心 实现

86IxXC

  • 要求
    登出链接: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