第三方登录之接入Github
第三方登录admin 发布于:2020-01-05 20:03:43
阅读:loading
这是本站实现的第6个第三方登录接入实现了,在此后很长一段时间应该不会再去实现其它的了(本来微信和360的登录也是可以有的,并不是接入难,而是资质审核麻烦),回顾这6种接入实现,还是往年实现的比较简单,都有官方提供的实现示例,而Gitee与Github则没有官方提供的实现,但它们的实现又是非常相似(非常非常),以至于我在实现Gitee后能够很轻易的实现基于Github的接入。本人实现这么多第三方站点的登录接入,主要有以下三个方面的意义:
(1)丰富个人的最佳实践,增加个人的技术领域深度;
(2)可以给本站增加一个新的来源的用户接入(让本站多放置一个按钮);
(3)提供友情接入接口,方便一些其它朋友站点(我接入多种来源的第三方登录,你们给我提供一个标识接入我即可,我将授权得到的用户ID、名称、头像、用户来源返回给你);
不多废话,整个接入过程建立在你已经拥有Github账号基础上,注册登录的不在介绍范围之内,详细介绍请见下文。
(1)登录Github,点击右上角的个人头像处下拉菜单中的Settings --> Developer settings --> Oauth Apps,新建一个Oauth项目,录入对应的站点信息,由Github生成Client ID、Client Secret等,参考如下图所示:
(2)查看对应API文档,实际上它的API文档找起来也是非常费劲的,特别是我这种英文水平非常渣渣的选手来说,真的是非常非常费劲,以登录授权的接口文档为例,查找它对应的文档地址如下,输入一下地址并以这种跟路径往下找,带你一起找到登录的接口文档,输入网址:https://developer.github.com,参考如下:
最终的文档地址参考如下:https://developer.github.com/apps/building-oauth-apps/authorizing-oauth-apps/ ,由于对第三方授权的套路早已熟悉于心,尽管API文档是英文的,但也表示压力不大,就是耐着兴致一步一步往下走。
package cn.chendd.third.login.controller;
import ...
/**
* 第三方登录 - Github登录
*
* @author chendd
* @date 2020/01/04 22:15
*/
@Api(tags = "Github账号登录")
@ApiSort(50)
@RequestMapping(value = "/third-login" , consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE , produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@RestController
@Slf4j
public class LoginGithubController extends ThirdLoginController {
@GetMapping(value = "/github" , consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE , produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ApiOperation(value = "github登录",notes = CALLBACK_NOTES)
@ApiOperationSupport(order = 10)
public String login(
@ApiParam(value = "朋友站点标识")
@RequestParam(required = false)
String friend) {
String link = super.getLink(friend);
GithubConfig config = super.getGithubConfig();
GithubOauth oauth = new GithubOauth(config , link);
return oauth.getAuthorize();
}
@GetMapping(value = "/githubCallback" , consumes = MediaType.ALL_VALUE , produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ApiOperation(value = "github登录回调",notes = "第三方登录 - Github登录回调,被动发起请求")
@ApiOperationSupport(order = 20)
public ThirdUserResult githubCallback(
@ApiParam(value = "github回调标识" , required = true) @RequestParam String code ,
@ApiParam("朋友站点标识") @RequestParam(value = "state" , required = false) String redirect) throws Exception {
//获取用户AccessToken
BaseResult baseTokenResult = this.getAccessToken(code, redirect);
String tokenResult = baseTokenResult.getResult();
if(! EnumResult.success.name().equals(tokenResult)){
throw new ValidateDataException(baseTokenResult.getMessage());
}
AccessTokenResult tokenResultData = (AccessTokenResult) baseTokenResult.getData();
BaseResult baseTokenUserResult = this.geAccessTokentUserInfo(tokenResultData.getAccessToken());
String tokenUserResult = baseTokenUserResult.getResult();
if(! EnumResult.success.name().equals(tokenUserResult)){
throw new ValidateDataException(baseTokenUserResult.getMessage());
}
AccessTokenUserInfoResult userInfoResult = (AccessTokenUserInfoResult) baseTokenUserResult.getData();
return new ThirdUserResult(String.valueOf(userInfoResult.getId()) ,
//如果没有设置昵称名,则以登录名为准
StringUtils.isBlank(userInfoResult.getName()) ? userInfoResult.getLogin() : userInfoResult.getName() ,
userInfoResult.getAvatarUrl() , EnumUserSource.Github , redirect);
}
/**
* 根据用户授权code获取授权token
*/
private BaseResult getAccessToken(String code , String redirect) {
GithubConfig config = super.getGithubConfig();
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
List<NameValuePair> params = new ArrayList<>();
params.add(new BasicNameValuePair("client_id" , config.getClientId()));
params.add(new BasicNameValuePair("client_secret" , config.getClientSecret()));
params.add(new BasicNameValuePair("code" , code));
params.add(new BasicNameValuePair("redirect_uri" , config.getRedirectUri()));
params.add(new BasicNameValuePair("state" , redirect));
CloseableHttpResponse response = null;
try {
String url = config.getAuthorizeURL() + "/access_token";
HttpPost httpPost = new HttpPost(url);
httpPost.setHeader("User-Agent" , "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:70.0) Gecko/20100101 Firefox/70.0");
httpPost.setEntity(new UrlEncodedFormEntity(params));
response = httpClient.execute(httpPost);
String result = EntityUtils.toString(response.getEntity());
if(StringUtils.contains(result , "access_token=") && StringUtils.contains(result ,"token_type=")){
return new SuccessResult<AccessTokenResult>(new AccessTokenResult(result));
}
return new ErrorResult(result);
} catch (Exception e) {
log.error("获取token请求异常" , e);
return new ErrorResult(String.format("获取token请求异常,参考:%s" , e.getMessage()));
} finally {
CloseUtil.close(response , httpClient);
}
}
/**
* 根据授权token获取对应的用户详细信息
*/
private BaseResult geAccessTokentUserInfo(String accessToken){
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
String url = super.getGithubConfig().getUserApiURL();
/**
* 经过验证,url=url?access_token=access_token的地址与从header中传递结果一致
*/
HttpGet httpGet = new HttpGet(url/* + "?access_token=" + accessToken*/);
httpGet.setHeader("User-Agent" , "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:70.0) Gecko/20100101 Firefox/70.0");
httpGet.setHeader("Authorization" , "token " + accessToken);
return super.consumesResponse(httpClient , httpGet , AccessTokenUserInfoResult.class);
}
}
//super.consumesResponse
protected <T> BaseResult consumesResponse(CloseableHttpClient httpClient , HttpGet httpGet , Class<T> clazz){
CloseableHttpResponse response = null;
try {
response = httpClient.execute(httpGet);
String result = EntityUtils.toString(response.getEntity());
return new SuccessResult<>(JSONObject.parseObject(result , clazz));
} catch (Exception e) {
log.error("根据token获取用户信息异常:" , e);
return new ErrorResult(String.format("根据token获取用户信息异常,参考:%s" , e.getMessage()));
} finally {
CloseUtil.close(response , httpClient);
}
}
userNumber:用户ID
nickName:用户昵称
protrait:用户头像
redirect:友链回调地址
userSource:用户来源
点赞