DOIFOR技术IDEA插件开发接入Gitea的Oauth2.0认证
DOIFOR技术IDEA插件开发接入Gitea的Oauth2.0认证
IDEA

IDEA插件开发接入Gitea的Oauth2.0认证

技术

官方文档: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应用,如下图:
file

没有勾选机密客户端,刚开始不清楚这个选项有什么用,后来在过去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的实现方法一致。

file

能拿到上述的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);
    }
}

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注