第三方登录:
vue-java前后端交互流程demo (本篇以gitee 为例)
时序图
sequenceDiagram
actor c as 客户端
participant f as 前端服务器
participant b as 后端服务器
participant g as gitee
rect rgb(213, 235, 225)
f ->> +g: 打开新窗口, 请求https://gitee.com/oauth/authorize
note over f, g: 携带client_id以及redirect_url (此处是不安全的)
g ->> g: 校验client_id
g ->> -b: 重定向至后端服务器
note over g,b: 携带code (此处是不安全的)
end
rect rgb(192, 214, 149)
b ->> +g: 请求https://gitee.com/oauth/token
note over b, g: 携带grant_type,client_id,client_secret,code,redirect_uri
g -->> -b: 返回access_token
end
rect rgb(240, 194, 162)
b ->> +g: 请求https://gitee.com/api/v5/user
note over b, g: 携带access_token
g -->> -b: 返回用户信息
end
rect rgb(235, 238, 232)
b ->> f: 生成token, 并将token信息发送给老窗口, 然后关闭新窗口
f ->> f: 监听到token
f ->> c: 将token写入到客户端浏览器
end
gitee
代码示例
- 前端打开新窗口, 并请求
gitee
giteeHandleClick(thirdpart) {
const client_id = 'client_idxxxxx' // giteeid
const redirect_uri = encodeURIComponent('http://uri/tp/gitee_cb') // gitee跳转地址
const url = `https://gitee.com/oauth/authorize?client_id=${client_id}&redirect_uri=${redirect_uri}&response_type=code`
window.open(url, thirdpart, 540, 540) // url,用户信息
}
- 后端接收
gitee所传code-> 获取access_token-> 获取用户信息 -> 生成用户token并返回给前端
public void gitee(String code, HttpServletResponse resp) throws IOException {
//获取访问令牌
String accessToken = this.getAccessToken(code);
//获取用户信息
Map<String, Object> body = this.getUserInfo(accessToken);
Object username = body.get("name");
Object avatar = body.get("avatar_url");
//用户信息存储本地, 生成JWT令牌给前端
String token = userService.loginFromOAuth(username.toString(), avatar.toString(), "");
//让页面去发送信息给前端调用者
String script = String.format("<script>\n" +
"window.opener.postMessage('%s','%s')\n" +
"window.close()\n" +
"</script>",
//给调用者发送信息,(详细内容,来源)指明消息来源, 否则会跨域
//window.opener.postMessage(message,origin)
//window.close() 关闭小窗口
token,
frontendURL);
resp.getWriter().print(script);
}
private String getAccessToken(String code) throws IOException {
String json = new ObjectMapper().writeValueAsString(MapBuilder.create()
.put("grant_type", "authorization_code")
.put("client_id", clientId)
.put("client_secret", clientSecret)
.put("code", code)
.put("redirect_uri", redirectURI).build()
);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> httpEntity = new HttpEntity<>(json, headers);
ResponseEntity<String> response = restTemplate.postForEntity("https://gitee.com/oauth/token", httpEntity, String.class);
Map body = new ObjectMapper().readValue(response.getBody(), Map.class);
return body.getOrDefault("access_token", "").toString();
}
private Map<String, Object> getUserInfo(String accessToken) throws IOException {
ResponseEntity<String> response = restTemplate.getForEntity(URI.create("https://gitee.com/api/v5/user?access_token=" + accessToken), String.class);
Map body = new ObjectMapper().readValue(response.getBody(), Map.class);
return body;
}
- 前端监听到token信息, 写入用户Cookie
window.addEventListener('message', msg => {
// 可以对消息来源做判断
if (msg.origin.toString().indexOf('8080') !== -1) {
setToken(msg.data)
window.location.href = '/' // 浏览器跳转
}
})
