AuthChecker.java 5.3 KB
Newer Older
智布道's avatar
智布道 已提交
1 2
package me.zhyd.oauth.utils;

智布道's avatar
智布道 已提交
3
import me.zhyd.oauth.cache.AuthStateCache;
智布道's avatar
智布道 已提交
4
import me.zhyd.oauth.config.AuthConfig;
5
import me.zhyd.oauth.config.AuthDefaultSource;
6
import me.zhyd.oauth.config.AuthSource;
智布道's avatar
智布道 已提交
7
import me.zhyd.oauth.enums.AuthResponseStatus;
8
import me.zhyd.oauth.exception.AuthException;
智布道's avatar
智布道 已提交
9
import me.zhyd.oauth.model.AuthCallback;
智布道's avatar
智布道 已提交
10 11

/**
智布道's avatar
智布道 已提交
12 13
 * 授权配置类的校验器
 *
智布道's avatar
智布道 已提交
14
 * @author yadong.zhang (yadong.zhang0415(a)gmail.com)
智布道's avatar
智布道 已提交
15
 * @since 1.6.1-beta
智布道's avatar
智布道 已提交
16
 */
17
public class AuthChecker {
智布道's avatar
智布道 已提交
18 19

    /**
智布道's avatar
智布道 已提交
20
     * 是否支持第三方登录
智布道's avatar
智布道 已提交
21
     *
22
     * @param config config
23
     * @param source source
智布道's avatar
智布道 已提交
24
     * @return true or false
智布道's avatar
智布道 已提交
25
     * @since 1.6.1-beta
智布道's avatar
智布道 已提交
26
     */
27
    public static boolean isSupportedAuth(AuthConfig config, AuthSource source) {
28 29
        boolean isSupported = StringUtils.isNotEmpty(config.getClientId())
            && StringUtils.isNotEmpty(config.getClientSecret());
30
        if (isSupported && AuthDefaultSource.STACK_OVERFLOW == source) {
31 32
            isSupported = StringUtils.isNotEmpty(config.getStackOverflowKey());
        }
智布道's avatar
智布道 已提交
33
        if (isSupported && AuthDefaultSource.WECHAT_ENTERPRISE == source) {
34 35
            isSupported = StringUtils.isNotEmpty(config.getAgentId());
        }
36 37
        if (isSupported && (AuthDefaultSource.CODING == source || AuthDefaultSource.OKTA == source)) {
            isSupported = StringUtils.isNotEmpty(config.getDomainPrefix());
智布道's avatar
智布道 已提交
38
        }
智布道's avatar
智布道 已提交
39 40 41 42 43 44
        if (isSupported && AuthDefaultSource.XMLY == source) {
            isSupported = StringUtils.isNotEmpty(config.getDeviceId()) && null != config.getClientOsType();
            if (isSupported) {
                isSupported = config.getClientOsType() == 3 || StringUtils.isNotEmpty(config.getPackId());
            }
        }
45 46 47 48 49 50 51 52
        return isSupported;
    }

    /**
     * 检查配置合法性。针对部分平台, 对redirect uri有特定要求。一般来说redirect uri都是http://,而对于facebook平台, redirect uri 必须是https的链接
     *
     * @param config config
     * @param source source
智布道's avatar
智布道 已提交
53
     * @since 1.6.1-beta
54
     */
55
    public static void checkConfig(AuthConfig config, AuthSource source) {
56
        String redirectUri = config.getRedirectUri();
57 58 59 60 61 62
        if (config.isIgnoreCheckRedirectUri()) {
            return;
        }
        if (StringUtils.isEmpty(redirectUri)) {
            throw new AuthException(AuthResponseStatus.ILLEGAL_REDIRECT_URI, source);
        }
63
        if (!GlobalAuthUtils.isHttpProtocol(redirectUri) && !GlobalAuthUtils.isHttpsProtocol(redirectUri)) {
智布道's avatar
智布道 已提交
64
            throw new AuthException(AuthResponseStatus.ILLEGAL_REDIRECT_URI, source);
65
        }
66
        // facebook的回调地址必须为https的链接
67
        if (AuthDefaultSource.FACEBOOK == source && !GlobalAuthUtils.isHttpsProtocol(redirectUri)) {
智布道's avatar
智布道 已提交
68 69
            // Facebook's redirect uri must use the HTTPS protocol
            throw new AuthException(AuthResponseStatus.ILLEGAL_REDIRECT_URI, source);
70
        }
71
        // 微软的回调地址必须为https的链接或者localhost,不允许使用http
72
        if (AuthDefaultSource.MICROSOFT == source && !GlobalAuthUtils.isHttpsProtocolOrLocalHost(redirectUri)) {
73 74 75 76
            // Microsoft's redirect uri must use the HTTPS or localhost
            throw new AuthException(AuthResponseStatus.ILLEGAL_REDIRECT_URI, source);
        }
        // 微软中国的回调地址必须为https的链接或者localhost,不允许使用http
77
        if (AuthDefaultSource.MICROSOFT_CN == source && !GlobalAuthUtils.isHttpsProtocolOrLocalHost(redirectUri)) {
78 79 80
            // Microsoft's redirect uri must use the HTTPS or localhost
            throw new AuthException(AuthResponseStatus.ILLEGAL_REDIRECT_URI, source);
        }
智布道's avatar
智布道 已提交
81
    }
82 83 84

    /**
     * 校验回调传回的code
智布道's avatar
智布道 已提交
85
     * <p>
86
     * {@code v1.10.0}版本中改为传入{@code source}和{@code callback},对于不同平台使用不同参数接受code的情况统一做处理
87
     *
智布道's avatar
智布道 已提交
88 89
     * @param source   当前授权平台
     * @param callback 从第三方授权回调回来时传入的参数集合
智布道's avatar
智布道 已提交
90
     * @since 1.8.0
91
     */
智布道's avatar
智布道 已提交
92
    public static void checkCode(AuthSource source, AuthCallback callback) {
93 94 95 96
        // 推特平台不支持回调 code 和 state
        if (source == AuthDefaultSource.TWITTER) {
            return;
        }
智布道's avatar
智布道 已提交
97
        String code = callback.getCode();
98
        if (source == AuthDefaultSource.HUAWEI) {
智布道's avatar
智布道 已提交
99 100
            code = callback.getAuthorization_code();
        }
101
        if (StringUtils.isEmpty(code)) {
智布道's avatar
智布道 已提交
102 103 104 105 106 107 108 109 110 111 112 113
            throw new AuthException(AuthResponseStatus.ILLEGAL_CODE, source);
        }
    }

    /**
     * 校验回调传回的{@code state},为空或者不存在
     * <p>
     * {@code state}不存在的情况只有两种:
     * 1. {@code state}已使用,被正常清除
     * 2. {@code state}为前端伪造,本身就不存在
     *
     * @param state          {@code state}一定不为空
114
     * @param source         {@code source}当前授权平台
智布道's avatar
智布道 已提交
115 116 117
     * @param authStateCache {@code authStateCache} state缓存实现
     */
    public static void checkState(String state, AuthSource source, AuthStateCache authStateCache) {
118 119 120 121
        // 推特平台不支持回调 code 和 state
        if (source == AuthDefaultSource.TWITTER) {
            return;
        }
智布道's avatar
智布道 已提交
122 123
        if (StringUtils.isEmpty(state) || !authStateCache.containsKey(state)) {
            throw new AuthException(AuthResponseStatus.ILLEGAL_STATUS, source);
124 125
        }
    }
智布道's avatar
智布道 已提交
126
}