github认证登陆
使用github OAuth实现用户登录
做登录功能时,允许使用第三方网站的身份,这称为"第三方登录"。
原理


github内的认证方法
在github上申请OAuth App,进入个人的Github首页,Settings->Applications->Developer applications->Register a new application


注册这个app的目的:You can enable other users to authorize your OAuth App.
您可以让其他用户授权您的OAuth应用程序。
获取code和state
<a href="https://github.com/login/oauth/authorize?client_id=1d1f99e3efc33edcbf45&redirect_uri=http://localhost:8080/callback&scope=user&state=1">登陆</a>
scope属性列出了用户授予的附加到令牌的范围。通常,这些范围将与您要求的范围相同。但是,用户可以编辑其范围,从而有效地授予您的应用程序比您最初请求的访问权限少的权限。此外,用户可以在OAuth流完成后编辑令牌作用域。您应该意识到这种可能性,并相应地调整应用程序的行为。
处理用户选择授予您的访问权限比您最初请求的权限少的错误情况非常重要。例如,应用程序可以警告其用户或以其他方式与其用户进行通信,告知他们功能将减少或无法执行某些操作。
此外,应用程序始终可以再次将用户发送回流程,以获取其他权限,但是请不要忘记用户总是可以拒绝。
client_id就是注册给的那个,redirect_uri就是你写的回调地址,通过访问这个地址获取令牌
| Name | Type | Description |
|---|---|---|
client_id |
string |
Required. The client ID you received from GitHub when you registered 必需的。注册时从GitHub收到的客户端ID。 |
redirect_uri |
string |
The URL in your application where users will be sent after authorization. See details below about redirect urls应用程序中的URL,用户将在授权后发送到该URL。请参阅下面关于重定向url的详细信息。 |
login |
string |
Suggests a specific account to use for signing in and authorizing the app.建议使用一个特定的帐户来登录和授权应用程序。 |
scope |
`string | 以空格分隔的范围列表。如果没有提供作用域,对于没有为应用程序授权任何作用域的用户,作用域默认为空列表。对于已经为应用程序授权了范围的用户,不会显示带有范围列表的OAuth授权页面。相反,流的这一步将使用用户为应用程序授权的范围集自动完成。例如,如果用户已经执行了两次web流,并且授权了一个具有用户范围的令牌和另一个具有回购范围的令牌,则第三个web流不提供sc |
state |
string |
An unguessable random string. It is used to protect against cross-site request forgery attacks.不可猜测的随机字符串。它用于防止跨站点请求伪造攻击。 |
allow_signup |
string |
Whether or not unauthenticated users will be offered an option to sign up for GitHub during the OAuth flow. The default is true. Use false in the case that a policy prohibits signups.在OAuth流期间,是否会为未经身份验证的用户提供一个注册GitHub的选项。默认值为true。在策略禁止注册的情况下使用false。 |
通过获取的code和state,利用httpclient来获取AccessToken
java代码callback接口如下:
@Value("${github.client.id}")
private String id;
@Value("${github.client.secret}")
private String secret;
@Value("${github.redirect.uri}")
private String uri;
@RequestMapping("/callback")
public String callback(@RequestParam(name = "code") String code,
@RequestParam(name = "state") String state,
HttpServletResponse response) {
//通过一个DTO对象封装,接收的code state
AccessTokenDTO accessTokenDTO = new AccessTokenDTO();
accessTokenDTO.setCode(code);
accessTokenDTO.setClient_id(id);
accessTokenDTO.setClient_secret(secret);
accessTokenDTO.setState(state);
accessTokenDTO.setRedirect_uri(uri);
//得到github传回来的数据 code + Client Secret+Client id来获取token
String accessToken = githubProvider.getAccessToken(accessTokenDTO);
//通过解析封装成一个对象
GithubUser githubUser = githubProvider.getUser(accessToken);
if (githubUser != null) {
//写入数据库
}
//login success
// request.getSession().setAttribute("user",githubUser);
return "redirect:/";
} else {
return "redirect:/";
}
利用获取过来的AccessToken来再次访问github来获取用户信息
其中githubprovider代码如下:
public String getAccessToken(AccessTokenDTO accessTokenDTO) {
//设置从GitHub那里获取的数据设置成josn格式
MediaType mediaType = MediaType.get("application/json; charset=utf-8");
OkHttpClient client = new OkHttpClient();
//通过okhttclient来获取github传过来的用户信息,要利用到AceessTokenDTO内的数据!
//将传过来的accesstokendto转化为json格式,通过post形式传给github
RequestBody body = RequestBody.create(mediaType, JSON.toJSONString(accessTokenDTO));
Request request = new Request.Builder()
.url("https://github.com/login/oauth/access_token")
.post(body)
.build();
try (Response response = client.newCall(request).execute()) {
String string = response.body().string();
//把传过来的token解析
String token = string.split("&")[0].split("=")[1];
return token;
} catch (Exception e) {
//log.error("getAccessToken error,{}", accessTokenDTO, e);
}
return null;
}
public GithubUser getUser(String accessToken) {
//通过得到的token获取user
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://api.github.com/user?access_token=" + accessToken)
.build();
try {
Response response = client.newCall(request).execute();
String string = response.body().string();
//封装
GithubUser githubUser = JSON.parseObject(string, GithubUser.class);
//System.out.println(string);
return githubUser;
} catch (Exception e) {
// log.error("getUser error,{}", accessToken, e);
}
return null;
}
获取的json内容如下:
//封装
JSON.parseObject(string, GithubUser.class); {
"login": "Diamondtest",
"id": 28478049,
"avatar_url": "https://avatars0.githubusercontent.com/u/28478049?v=3",
"gravatar_id": "",
"url": "https://api.github.com/users/Diamondtest",
"html_url": "https://github.com/Diamondtest",
"followers_url": "https://api.github.com/users/Diamondtest/followers",
"following_url": "https://api.github.com/users/Diamondtest/following{/other_user}",
"gists_url": "https://api.github.com/users/Diamondtest/gists{/gist_id}",
"starred_url": "https://api.github.com/users/Diamondtest/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/Diamondtest/subscriptions",
"organizations_url": "https://api.github.com/users/Diamondtest/orgs",
"repos_url": "https://api.github.com/users/Diamondtest/repos",
"events_url": "https://api.github.com/users/Diamondtest/events{/privacy}",
"received_events_url": "https://api.github.com/users/Diamondtest/received_events",
"type": "User",
"site_admin": false,
"name": null,
"company": null,
"blog": "",
"location": null,
"email": null,
"hireable": null,
"bio": null,
"public_repos": 0,
"public_gists": 0,
"followers": 0,
"following": 0,
"created_at": "2017-05-06T08:08:09Z",
"updated_at": "2017-05-06T08:16:22Z"
}
授权之后,每次登陆都不需要再次授权,可更换浏览器或者选择revoke all user tokens 就可以了!

okhttpclient的用例与介绍
介绍
OkHttp是一个HTTP客户机,默认情况下是高效的:
http/2支持允许对同一主机的所有请求共享套接字。
连接池可以减少请求延迟(如果HTTP/2不可用)。
透明GZIP缩小下载大小。
响应缓存完全避免了重复请求的网络。
OkHttpClient client = new OkHttpClient();
//获取URL
//访问URL并获取该网站返回过来的字符串
String run(String url) throws IOException {
Request request = new Request.Builder()
.url(url)
.build();
try (Response response = client.newCall(request).execute()) {
return response.body().string();
}
} public static final MediaType JSON
= MediaType.get("application/json; charset=utf-8");
OkHttpClient client = new OkHttpClient();
//发送到服务器
//通过build一个request 并将需要的参数封装到body 访问url,执行client.newCall(request).execute(),得到返回值,一般是一个json格式的字符串,当然也可以自己选择它的返回数据格式!
String post(String url, String json) throws IOException {
RequestBody body = RequestBody.create(json, JSON);
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
try (Response response = client.newCall(request).execute()) {
return response.body().string();
}
}
详情参见:okhttp
github认证登陆的更多相关文章
- Liferay7 BPM门户开发之32: 实现自定义认证登陆(定制Authentication Hook)
第一步:修改liferay-hook.xml <?xml version="1.0"?> <!DOCTYPE hook PUBLIC "-//Lifer ...
- 2)实现github自动登陆获取信息
# -*- coding:utf-8 -*- # __author__ = 'lixiang' # 实现github自动登陆和获取数据 import requests from bs4 import ...
- 我了解到的新知识之—Apple Captive Portal 网页认证登陆公共Wifi
因为今天一个用户遇到选择公司WiFi后,无法弹出网页认证登陆界面的问题,随即上网搜索相关信息,因为公司内没有VPN,无法FQ,只能用bing来搜索一下相关信息了. Captive Portal听起来好 ...
- 04 自学Aruba之定制AC的protal认证登陆页面
点击返回:自学Aruba之路 04 自学Aruba之定制AC的protal认证登陆页面 方法一: 使用Aruba控制器中内置的网页界面 Configuration下MANAGEMENT>Capt ...
- Github第三方登陆详细流程
一. 流程图 二.具体实现步骤 Ⅰ.创建OAuth App 我们首先需要创建一个OAuth App,根据下图的步骤点击即可 依次填写信息,然后点Register application 然后我们可以看 ...
- JMeter CSRFToken认证登陆(正则提取器的使用)
转自:http://blog.csdn.net/lion19930924/article/details/51189210 前几天用JMeter模拟登陆,但是这个网站开启了csrf认证,因此在post ...
- linux SecureCRT ssh key认证登陆
转自:http://blog.chinaunix.net/uid-20639775-id-3207171.html 通过SecureCRT创建key登录认证 一.生成公钥/密钥对 使用SecureCR ...
- SharePoint2013基于Form(FBA)的AD认证登陆
来源于:http://www.haogongju.net/art/1964313 1. 使用SharePoint2013实现基于AD的Form认证,首先创建一个Web Application,步骤如下 ...
- asp.net core 基于角色的认证登陆
一.登陆页面的Controller [Authorize(Roles = "Admin,SuperAdmin")] public class ManageController : ...
随机推荐
- MinorGC 和 FullGC的理解
1.GC回收机制熟悉么,分代算法知道么?2.了解 Java 虚拟机的垃圾回收算法? 从年轻代空间(包括 Eden 和 Survivor 区域)回收内存被称为 Minor GC. Major GC 是清 ...
- 使用Python的Django和layim实现即时通讯
看到Django和layim实现websocketde资料很少,自己就琢磨了下,顺便搭建出来了.自己要去找闲心大神授权呀. 先来看图 这是初次搭建的,今天一天就搞定.我自己接入了图灵机器人. Pyt ...
- jquery实现表格导入到Excel(加图片)
话不多说直接上代码 第一步:导入jquery的插件https://github.com/rainabba/jquery-table2excel HTML部分: 第二步:添加一个按钮 <but ...
- Codeforces 975C
题意略. 思路:这题考察的是二分搜索. #include<bits/stdc++.h> #define maxn 200005 using namespace std; typedef l ...
- Mysql分区实战
一,什么是数据库分区 前段时间写过一篇关于MySQL分表的的文章,下面来说一下什么是数据库分区,以mysql为例.mysql数据库中的数据是以文件的形势存在磁盘上的,默认放在/mysql/data下面 ...
- 【CF #541 D】 Gourmet choice
link:https://codeforces.com/contest/1131 题意: 给定一些大小比较,输出排名. 思路: 这道题我用的是拓扑排序,又因为有等于号的存在,我用了并查集. 结束后这道 ...
- Aizu-2249 Road Construction(dijkstra求最短路)
Aizu - 2249 题意:国王本来有一个铺路计划,后来发现太贵了,决定删除计划中的某些边,但是有2个原则,1:所有的城市必须能达到. 2:城市与首都(1号城市)之间的最小距离不能变大. 并且在这2 ...
- HDU - 3966 树链刨分
题目传送门 操作就是询问某个点的值, 然后就是对一条路径上的值全部修改. 最基本的树刨题目了. 树刨的思想: 1. 对于每个点找到他的重儿子. void dfs1(int o, int u){ sz[ ...
- HDU 4565 So Easy! 广义斐波拉数 数论 (a+sqrt(b))^n%mod 模板
So Easy! Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Su ...
- 求解区间问题的三种做法的区别 线段树、树状数组、RMQ
树状数组主要用于计算区间的和,在区间元素修改值的时候能够快速修改而不是以O(n)的复杂度进行修改: 线段树是把区间以树的形式分拆为若干个小区间,每个小区间存的都有一个值(树状数组的元素存的是区间值), ...