前言:毕业设计终于好了,希望能有空多写几篇
1. 获取Github账号的Client ID和Client secrets
首先点击这个链接进入Github的OAuth Apps页面,页面展示如下:
之后我们可以创建一个新的apps:
填写资料:
创建之后就可以获取到Client ID 和 Client Scrects
2. github用户信息获取流程
获取到Client ID 和 Client Scrects之后,就可以开始写代码了,这里先放上接口文档
2.1 获取授权码Authorize Code
请求路径:
GET https://github.com/login/oauth/authorize
主要携带参数:
参数名称 | 类型 | 描述 |
---|---|---|
client_id | string | 必需带上,注册时从GitHub收到的客户端ID。 |
redirect_uri | string | 应用程序中的URL,授权后用户将被发送到该URL。 |
scope | string | 用空格分隔的作用域列表。如果未提供,则范围默认为未为应用程序授权任何范围的用户的空列表。对于已授权应用程序范围的用户,不会向用户显示包含范围列表的OAuth授权页面。 |
state | string | 一个随机字符串,用于防止跨站点请求伪造攻击。 |
allow_signup | string | 在OAuth流程中,是否会向未经身份验证的用户提供注册GitHub的选项。默认为true。当策略禁止注册时使用false。 |
请求的响应结果:
前面参数中的redirect_uri
填写的返回路径,同时这个返回路径会携带code和state,基于此,我们可以在前端定义一个跳转到 Github 授权页面的链接:
<a href="https://github.com/login/oauth/authorize?scope=user:email&client_id=请填写自己的client_id">Github登录</a>
(ps:这里我使用了个图标,一样的)
点击之后就有了这个画面:
输入正确的密码之后,GitHub将重定向回站点,并在代码参数中携带code以及在前一步中提供的状态参数state。临时代码将在10分钟后失效。如果状态不匹配,则是第三方创建了请求,开发者应该中止该过程。
我们就可以使用Vue中的route获取这个code参数,
这里我的router.js中配置了返回路径对应路由:
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
export default routes: [
{
path: "/",
name: "post",
component: Post,
},
]});
然后在页面中拿到这个code
onMounted(async() => {
let code = route.query.code;
if(code === undefined || code === null || code === ""){
message.error("登录失败:code为空");
return;
}
//然后发送这个code给后端就行了,很简单,不多赘述
});
2.2 通过授权码获取access_token
请求URL:
POST https://github.com/login/oauth/access_token
携带参数:
参数名称 | 类型 | 描述 |
---|---|---|
client_id | string | 必需!前面的获取Client ID |
client_secret | string | 必需!前面获取的Client Secret |
code | string | 必需!上一步获取到的code |
返回参数:
Accept: application/json
{
"access_token":"gho_16C7e42F292c6912E7710c838347Ae178B4a",
"scope":"repo,gist",
"token_type":"bearer"
}
于是乎我们拿到了access_token
代码编写如下:
Map<String, Object> data = new HashMap<>();
data.put("client_id", 你的client_id);
data.put("client_secret", 你的client_secret);
data.put("code", 收到的code);
// 使用HttpUtil发送post请求
String post = HttpRequest.post(accessTokenURL)
.header(Header.ACCEPT, "application/json")
.body(JSONUtil.toJsonStr(data))
.execute().body();
然后再获取access-token:
String accessToken = null;
try{
JSONObject postResponse = JSONObject.parseObject(post);
accessToken = postResponse.getString("access_token"); //获取密钥
if(accessToken == null || accessToken.equals("")){
throw new BusinessException(ErrorCode.LOGIN_ERROR);
}
}
catch (Exception e){
throw new BusinessException(ErrorCode.LOGIN_ERROR);
}
2.3 根据access_token获取用户信息进行登录
请求地址:
Authorization: token ${access_token}
GET https://api.github.com/user
返回参数:
{
"login": "STUkkkkkk",
"id": 98441370,
"node_id": "U_kgDOBd4Ymg",
"avatar_url": "https://avatars.githubusercontent.com/u/98441370?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/STUkkkkkk",
"html_url": "https://github.com/STUkkkkkk",
"followers_url": "https://api.github.com/users/STUkkkkkk/followers",
"following_url": "https://api.github.com/users/STUkkkkkk/following{/other_user}",
"gists_url": "https://api.github.com/users/STUkkkkkk/gists{/gist_id}",
"starred_url": "https://api.github.com/users/STUkkkkkk/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/STUkkkkkk/subscriptions",
"organizations_url": "https://api.github.com/users/STUkkkkkk/orgs",
"repos_url": "https://api.github.com/users/STUkkkkkk/repos",
"events_url": "https://api.github.com/users/STUkkkkkk/events{/privacy}",
"received_events_url": "https://api.github.com/users/STUkkkkkk/received_events",
"type": "User",
"site_admin": false,
"name": "小坤(Stukk)",
"company": null,
"blog": "",
"location": null,
"email": null,
"hireable": null,
"bio": "学习!",
"twitter_username": null,
"public_repos": 6,
"public_gists": 0,
"followers": 0,
"following": 1,
"created_at": "2022-01-26T03:23:04Z",
"updated_at": "2024-03-02T11:57:33Z",
"private_gists": 0,
"total_private_repos": 2,
"owned_private_repos": 2,
"disk_usage": 33800,
"collaborators": 0,
"two_factor_authentication": false,
"plan": {
"name": "free",
"space": 976562499,
"collaborators": 0,
"private_repos": 10000
}
}
我们就可以封装这些数据进行登录啦!
代码:
// 获取github用户信息
String userInfoURL = gitHubConstants.getUserInfoURL(); //获取用户登录信息的请求地址
String userInfo = HttpRequest.get("https://api.github.com/user")
.header(Header.AUTHORIZATION, "token " + accessToken)
.header("X-GitHub-Api-Version", "2022-11-28")
.execute().body();
JSONObject userInfoJson = JSONObject.parseObject(userInfo);
String githubId = userInfoJson.getString("id"); //这个是github的id
LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
userLambdaQueryWrapper.eq(User::getGithubId,githubId);
User user = this.getOne(userLambdaQueryWrapper);
if(user != null){
// 3. 记录用户的登录态
request.getSession().setAttribute(USER_LOGIN_STATE, user);
return this.getLoginUserVO(user);
}
//接下来看你的业务去写代码了
2.4 根据access_token获取用户邮箱
和上面一样,就是把user换成emails
Authorization: token ${access_token}
GET https://api.github.com/emails
响应结果:
[
{
"email": "xxx@qq.com",
"primary": true,
"verified": true,
"visibility": "private"
},
{
"email": "xxx@users.noreply.github.com",
"primary": false,
"verified": true,
"visibility": null
}
]
和前面的user一样,不赘述了。
3. 将Github用户信息与数据库进行比对,进行登录注册
到此我们已经拿到了Github用户的信息,我们通过比对githubId来看看是否出现在数据库中,不在的话就进行注册,存在的话就登陆操作。
比如我们可以数据库记录的是用户的id,githubId,用户名,邮箱等等如果用户第一次登录,插入一条记录,如果不是就进行数据库数据的比对进行登录,如果有错误,终止登录流程并进行提示。没有错误就把页面重定向到对应的前端页面,并且把用户信息返回给前端,这样就完成了第三方登录了!