# 目录


# 自定义第三方平台的OAuth

JustAuth (opens new window)发展到现在,基本上已经涵盖了国内外大多数知名的网站。JustAuth (opens new window)也一直以它的,备受各位朋友的厚爱、支持。

但现在OAuth技术越来越成熟,越来越多的个人站长或者企业都开始搭建自己的OAuth授权平台,那么针对这种情况,JustAuth (opens new window)并不能做到面面俱到,无法去集成所有支持OAuth的网站(这也是不现实的)。

既然考虑到有这种需求,那么就要想办法解决,想办法填补漏洞,不为了自己,也为了陪伴JustAuth (opens new window)一路走来的所有朋友们。

JustAuth (opens new window)开发团队也在v1.12.0 (opens new window)版本中新加入了一大特性,就是可以支持任意支持OAuth的网站通过JustAuth实现便捷的OAuth登录!

下面我们会通过一个小例子,讲解如何使用JustAuth集成自己搭建的GitLab服务。

提示

本节将会使用JustAuth-demo (opens new window)项目进行演示

# 搭建Gitlab服务

请自行解决,如果已有搭建好的Gitlab私服,请直接进入下面的步骤

# 创建应用

gitlab私服创建应用 gitlab私服应用详情

# 实现AuthSource接口

AuthSource.java是为了提供OAuth平台的API地址的统一接口,提供以下方法供实现:

  • AuthSource#authorize(): 获取授权url. 必须实现
  • AuthSource#accessToken(): 获取accessToken的url. 必须实现
  • AuthSource#userInfo(): 获取用户信息的url. 必须实现
  • AuthSource#revoke(): 获取取消授权的url. 非必须实现接口(部分平台不支持)
  • AuthSource#refresh(): 获取刷新授权的url. 非必须实现接口(部分平台不支持)

注:

  • 当通过JustAuth扩展实现第三方授权时,请参考AuthDefaultSource自行创建对应的枚举类并实现AuthSource接口
  • 如果不是使用的枚举类,那么在授权成功后获取用户信息时,需要单独处理source字段的赋值
  • 如果扩展了对应枚举类时,在me.zhyd.oauth.request.AuthRequest#login(AuthCallback)中可以通过xx.toString()获取对应的source
package me.zhyd.justauth;

import me.zhyd.oauth.config.AuthSource;

/**
 * @author yadong.zhang (yadong.zhang0415(a)gmail.com)
 * @version 1.0
 * @website https://www.zhyd.me
 * @date 2019/10/26 16:54
 * @since 1.8
 */
public enum AuthCustomSource implements AuthSource {

    /**
     * 自己搭建的gitlab私服
     */
    MYGITLAB {
        /**
         * 授权的api
         *
         * @return url
         */
        @Override
        public String authorize() {
            return "http://gitlab.xxx.com/oauth/authorize";
        }

        /**
         * 获取accessToken的api
         *
         * @return url
         */
        @Override
        public String accessToken() {
            return "http://gitlab.xxx.com/oauth/token";
        }

        /**
         * 获取用户信息的api
         *
         * @return url
         */
        @Override
        public String userInfo() {
            return "http://gitlab.xxx.com/api/v4/user";
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

# 创建自定义的Request

package me.zhyd.justauth;

import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson.JSONObject;
import me.zhyd.oauth.cache.AuthStateCache;
import me.zhyd.oauth.config.AuthConfig;
import me.zhyd.oauth.enums.AuthUserGender;
import me.zhyd.oauth.exception.AuthException;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthToken;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.request.AuthDefaultRequest;
import me.zhyd.oauth.utils.UrlBuilder;

/**
 * @author yadong.zhang (yadong.zhang0415(a)gmail.com)
 * @version 1.0
 * @website https://www.zhyd.me
 * @date 2019/10/26 17:00
 * @since 1.8
 */
public class AuthMyGitlabRequest extends AuthDefaultRequest {


    public AuthMyGitlabRequest(AuthConfig config) {
        super(config, AuthCustomSource.MYGITLAB);
    }

    public AuthMyGitlabRequest(AuthConfig config, AuthStateCache authStateCache) {
        super(config, AuthCustomSource.MYGITLAB, authStateCache);
    }

    @Override
    protected AuthToken getAccessToken(AuthCallback authCallback) {
        HttpResponse response = doPostAuthorizationCode(authCallback.getCode());
        JSONObject object = JSONObject.parseObject(response.body());

        this.checkResponse(object);

        return AuthToken.builder()
                .accessToken(object.getString("access_token"))
                .refreshToken(object.getString("refresh_token"))
                .idToken(object.getString("id_token"))
                .tokenType(object.getString("token_type"))
                .scope(object.getString("scope"))
                .build();
    }

    @Override
    protected AuthUser getUserInfo(AuthToken authToken) {
        HttpResponse response = doGetUserInfo(authToken);
        JSONObject object = JSONObject.parseObject(response.body());

        this.checkResponse(object);

        return AuthUser.builder()
                .uuid(object.getString("id"))
                .username(object.getString("username"))
                .nickname(object.getString("name"))
                .avatar(object.getString("avatar_url"))
                .blog(object.getString("web_url"))
                .company(object.getString("organization"))
                .location(object.getString("location"))
                .email(object.getString("email"))
                .remark(object.getString("bio"))
                .gender(AuthUserGender.UNKNOWN)
                .token(authToken)
                .source(source.toString())
                .build();
    }

    private void checkResponse(JSONObject object) {
        // oauth/token 验证异常
        if (object.containsKey("error")) {
            throw new AuthException(object.getString("error_description"));
        }
        // user 验证异常
        if (object.containsKey("message")) {
            throw new AuthException(object.getString("message"));
        }
    }

    /**
     * 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
     *
     * @param state state 验证授权流程的参数,可以防止csrf
     * @return 返回授权地址
     * @since 1.11.0
     */
    @Override
    public String authorize(String state) {
        return UrlBuilder.fromBaseUrl(super.authorize(state))
                .queryParam("scope", "read_user+openid")
                .build();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96

# 测试效果

创建AuthMyGitlabRequest

AuthRequest authRequest = new AuthMyGitlabRequest(AuthConfig.builder()
    .clientId("63398e403231d4aa7e856cf5413620d536a876cb94e8d10ced0d3191b5d1d246")
    .clientSecret("65b0eba68fff019e682e6755882a24dfdbf0a61be55de119cb8970320186c8eb")
    .redirectUri("http://127.0.0.1:8443/oauth/callback/mygitlab")
    .build());
1
2
3
4
5

注:完整代码都在JustAuth-demo (opens new window)Demo项目中,本节只讲解关键代码

登录后的效果为

gitlab私服验证授权 gitlab私服登录完成

上次更新: 1/7/2021, 12:40:15 PM