官方文档:OAuth2 提供者
咱们采用code模式接入,首先是需要拼接获取code的链接:
private String loginUrl() {
return "https://abc.com/login/oauth/authorize?client_id=" + clientId
+ "&redirect_uri=" + redirect + "&response_type=code&state=" + UUID.randomUUID();
}
参数说明:
- clientId: 为gitea上创建应用的时候分配的
- redirect:是插件中用于接受code的一个接口,可以在idea中启动要给webserver,也可以在服务端开一个接口用来接收这些参数
- state:是一个随机字符串,Oauth服务器会返回code的时候将state原样返回,这个可以用来做很多事情,具体看情况。
由于在gitea创建应用的时候选择了public应用,如下图:
没有勾选机密客户端,刚开始不清楚这个选项有什么用,后来在过去code的时候报错了,返回地址为:
http://localhost:9864/?error=invalid_request&error_description=PKCE+is+required+for+public+clients&state=9ae77b3e-a0f5-4703-a122-977f1cba9a87
提示说:pkce is required for public client
搜索了以下,发现非机密客户端需要使用 Proof Key for Code Exchange (PKCE),在知乎上找到一篇文章对这个知识点进行了讲解:08. 周末福利之二!抢鲜更新之锦上添花:PKCE和授权码模式,然后再参照了CSDN上OAuth 2.0 扩展协议之 PKCE进行实现。
Java的实现代码如下:
private String loginUrl() {
return "https://abc.com/login/oauth/authorize?client_id=" + clientId
+ "&redirect_uri=" + redirect + "&response_type=code&state=" + UUID.randomUUID()
+ "&code_challenge=" + getChallengeStr()
+ "&code_challenge_method=S256";
}
private static String getChallengeStr() {
byte[] challenge = new byte[128];
SecureRandom random = new SecureRandom();
random.nextBytes(challenge);
MessageDigest digest;
try {
digest = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
digest.update(challenge);
byte[] hash = digest.digest();
return Base64.encodeBase64URLSafeString(hash);
}
主要实现方法就是在获取code的链接上添加上code_challenge和code_challenge_method两个参数,然后就可以实现code获取了,后续流程与其他Oauth2.0的实现方法一致。
能拿到上述的code,就可以继续参照官方文档获取用户、仓库等下信息了。
另外补充以下IDEA插件开发之快速启动HTTP服务中方法二的参数解析方式,这里需要使用到URIBuilder
对象,实现代码如下:
if (httpRequest instanceof BasicHttpRequest basicHttpRequest) {
try {
String query = basicHttpRequest.getRequestLine().getUri();
if (query != null) {
URIBuilder uriBuilder = new URIBuilder(query);
Map<String, String> params = uriBuilder.getQueryParams().stream()
.collect(Collectors.toMap(NameValuePair::getName, NameValuePair::getValue));
// 此处就可以获取到code 和 state 两个参数了
BasicHttpEntity entity = new BasicHttpEntity();
entity.setContent(new ByteArrayInputStream("登录成功,请关闭当前页面!".getBytes()));
httpResponse.setEntity(entity);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}