AuthAlipayRequest.java 10.2 KB
Newer Older
1 2
package me.zhyd.oauth.request;

3
import com.alibaba.fastjson.JSONObject;
4 5 6 7 8 9 10
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipaySystemOauthTokenRequest;
import com.alipay.api.request.AlipayUserInfoShareRequest;
import com.alipay.api.response.AlipaySystemOauthTokenResponse;
import com.alipay.api.response.AlipayUserInfoShareResponse;
11
import me.zhyd.oauth.cache.AuthStateCache;
12
import me.zhyd.oauth.config.AuthConfig;
13
import me.zhyd.oauth.config.AuthDefaultSource;
14
import me.zhyd.oauth.enums.AuthResponseStatus;
智布道's avatar
智布道 已提交
15
import me.zhyd.oauth.enums.AuthUserGender;
16
import me.zhyd.oauth.exception.AuthException;
17
import me.zhyd.oauth.model.AuthCallback;
18
import me.zhyd.oauth.model.AuthResponse;
19
import me.zhyd.oauth.model.AuthToken;
20
import me.zhyd.oauth.model.AuthUser;
21 22
import me.zhyd.oauth.utils.AuthChecker;
import me.zhyd.oauth.utils.GlobalAuthUtils;
23
import me.zhyd.oauth.utils.StringUtils;
不合群的混子's avatar
不合群的混子 已提交
24
import me.zhyd.oauth.utils.UrlBuilder;
25

cly_0's avatar
还原  
cly_0 已提交
26 27
import java.net.InetSocketAddress;

28
/**
29 30
 * 支付宝登录
 *
31
 * @author yadong.zhang (yadong.zhang0415(a)gmail.com)
智布道's avatar
智布道 已提交
32
 * @since 1.0.1
33
 */
智布道's avatar
智布道 已提交
34
public class AuthAlipayRequest extends AuthDefaultRequest {
35

36 37 38 39 40 41 42
    /**
     * 支付宝公钥:当选择支付宝登录时,该值可用
     * 对应“RSA2(SHA256)密钥”中的“支付宝公钥”
     */
    private final String alipayPublicKey;

    private final AlipayClient alipayClient;
43

44 45 46 47 48
    /**
     * @see AuthAlipayRequest#AuthAlipayRequest(me.zhyd.oauth.config.AuthConfig, java.lang.String)
     * @deprecated 请使用带有"alipayPublicKey"参数的构造方法
     */
    @Deprecated
49
    public AuthAlipayRequest(AuthConfig config) {
50
        this(config, (String) null);
51 52
    }

53 54 55 56 57
    /**
     * @see AuthAlipayRequest#AuthAlipayRequest(me.zhyd.oauth.config.AuthConfig, java.lang.String, me.zhyd.oauth.cache.AuthStateCache)
     * @deprecated 请使用带有"alipayPublicKey"参数的构造方法
     */
    @Deprecated
58
    public AuthAlipayRequest(AuthConfig config, AuthStateCache authStateCache) {
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
        this(config, null, authStateCache);
    }

    /**
     * @see AuthAlipayRequest#AuthAlipayRequest(me.zhyd.oauth.config.AuthConfig, java.lang.String, me.zhyd.oauth.cache.AuthStateCache, java.lang.String, java.lang.Integer)
     * @deprecated 请使用带有"alipayPublicKey"参数的构造方法
     */
    @Deprecated
    public AuthAlipayRequest(AuthConfig config, AuthStateCache authStateCache, String proxyHost, Integer proxyPort) {
        this(config, null, authStateCache, proxyHost, proxyPort);
    }

    /**
     * 构造方法,需要设置"alipayPublicKey"
     *
     * @param config          公共的OAuth配置
     * @param alipayPublicKey 支付宝公钥
     * @see AuthAlipayRequest#AuthAlipayRequest(me.zhyd.oauth.config.AuthConfig)
     */
    public AuthAlipayRequest(AuthConfig config, String alipayPublicKey) {
        super(config, AuthDefaultSource.ALIPAY);
        this.alipayPublicKey = determineAlipayPublicKey(alipayPublicKey, config);
        this.alipayClient = new DefaultAlipayClient(AuthDefaultSource.ALIPAY.accessToken(), config.getClientId(), config.getClientSecret(), "json", "UTF-8", alipayPublicKey, "RSA2");
        check(config);
    }

    /**
     * 构造方法,需要设置"alipayPublicKey"
     *
     * @param config          公共的OAuth配置
     * @param alipayPublicKey 支付宝公钥
     * @see AuthAlipayRequest#AuthAlipayRequest(me.zhyd.oauth.config.AuthConfig, me.zhyd.oauth.cache.AuthStateCache)
     */
    public AuthAlipayRequest(AuthConfig config, String alipayPublicKey, AuthStateCache authStateCache) {
93
        super(config, AuthDefaultSource.ALIPAY, authStateCache);
94
        this.alipayPublicKey = determineAlipayPublicKey(alipayPublicKey, config);
cly_0's avatar
还原  
cly_0 已提交
95 96 97
        if (config.getHttpConfig() != null && config.getHttpConfig().getProxy() != null
            && config.getHttpConfig().getProxy().address() instanceof InetSocketAddress) {
            InetSocketAddress address = (InetSocketAddress) config.getHttpConfig().getProxy().address();
cly_0's avatar
1  
cly_0 已提交
98
            this.alipayClient = new DefaultAlipayClient(AuthDefaultSource.ALIPAY.accessToken(), config.getClientId(), config.getClientSecret(),
99
                "json", "UTF-8", alipayPublicKey, "RSA2", address.getHostName(), address.getPort());
cly_0's avatar
cly_0 已提交
100
        } else {
cly_0's avatar
cly_0 已提交
101
            this.alipayClient = new DefaultAlipayClient(AuthDefaultSource.ALIPAY.accessToken(), config.getClientId(), config.getClientSecret(),
102
                "json", "UTF-8", alipayPublicKey, "RSA2");
cly_0's avatar
1  
cly_0 已提交
103
        }
104
        check(config);
105 106
    }

107 108 109 110 111 112 113 114
    /**
     * 构造方法,需要设置"alipayPublicKey"
     *
     * @param config          公共的OAuth配置
     * @param alipayPublicKey 支付宝公钥
     * @see AuthAlipayRequest#AuthAlipayRequest(me.zhyd.oauth.config.AuthConfig, me.zhyd.oauth.cache.AuthStateCache, java.lang.String, java.lang.Integer)
     */
    public AuthAlipayRequest(AuthConfig config, String alipayPublicKey, AuthStateCache authStateCache, String proxyHost, Integer proxyPort) {
115
        super(config, AuthDefaultSource.ALIPAY, authStateCache);
116
        this.alipayPublicKey = determineAlipayPublicKey(alipayPublicKey, config);
117
        this.alipayClient = new DefaultAlipayClient(AuthDefaultSource.ALIPAY.accessToken(), config.getClientId(), config.getClientSecret(),
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
            "json", "UTF-8", alipayPublicKey, "RSA2", proxyHost, proxyPort);
        check(config);
    }

    private String determineAlipayPublicKey(String alipayPublicKey, AuthConfig config) {
        return alipayPublicKey != null ? alipayPublicKey : config.getAlipayPublicKey();
    }

    protected void check(AuthConfig config) {
        AuthChecker.checkConfig(config, AuthDefaultSource.ALIPAY);

        if (!StringUtils.isNotEmpty(alipayPublicKey)) {
            throw new AuthException(AuthResponseStatus.PARAMETER_INCOMPLETE, AuthDefaultSource.ALIPAY);
        }

        // 支付宝在创建回调地址时,不允许使用localhost或者127.0.0.1
        if (GlobalAuthUtils.isLocalHost(config.getRedirectUri())) {
            // The redirect uri of alipay is forbidden to use localhost or 127.0.0.1
            throw new AuthException(AuthResponseStatus.ILLEGAL_REDIRECT_URI, AuthDefaultSource.ALIPAY);
        }
    }

    @Override
    protected void checkCode(AuthCallback authCallback) {
        if (StringUtils.isEmpty(authCallback.getAuth_code())) {
            throw new AuthException(AuthResponseStatus.ILLEGAL_CODE, source);
        }
145 146
    }

147
    @Override
148
    protected AuthToken getAccessToken(AuthCallback authCallback) {
149 150
        AlipaySystemOauthTokenRequest request = new AlipaySystemOauthTokenRequest();
        request.setGrantType("authorization_code");
智布道's avatar
智布道 已提交
151
        request.setCode(authCallback.getAuth_code());
cly_0's avatar
cly_0 已提交
152
        AlipaySystemOauthTokenResponse response;
153 154 155
        try {
            response = this.alipayClient.execute(request);
        } catch (Exception e) {
智布道's avatar
智布道 已提交
156
            throw new AuthException(e);
157 158 159 160
        }
        if (!response.isSuccess()) {
            throw new AuthException(response.getSubMsg());
        }
161
        return AuthToken.builder()
不合群的混子's avatar
不合群的混子 已提交
162 163 164 165 166
            .accessToken(response.getAccessToken())
            .uid(response.getUserId())
            .expireIn(Integer.parseInt(response.getExpiresIn()))
            .refreshToken(response.getRefreshToken())
            .build();
167 168
    }

169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
    /**
     * 刷新access token (续期)
     *
     * @param authToken 登录成功后返回的Token信息
     * @return AuthResponse
     */
    @Override
    public AuthResponse refresh(AuthToken authToken) {
        AlipaySystemOauthTokenRequest request = new AlipaySystemOauthTokenRequest();
        request.setGrantType("refresh_token");
        request.setRefreshToken(authToken.getRefreshToken());
        AlipaySystemOauthTokenResponse response = null;
        try {
            response = this.alipayClient.execute(request);
        } catch (Exception e) {
            throw new AuthException(e);
        }
        if (!response.isSuccess()) {
            throw new AuthException(response.getSubMsg());
        }
        return AuthResponse.builder()
            .code(AuthResponseStatus.SUCCESS.getCode())
            .data(AuthToken.builder()
                .accessToken(response.getAccessToken())
                .uid(response.getUserId())
                .expireIn(Integer.parseInt(response.getExpiresIn()))
                .refreshToken(response.getRefreshToken())
                .build())
            .build();
    }

200
    @Override
201 202
    protected AuthUser getUserInfo(AuthToken authToken) {
        String accessToken = authToken.getAccessToken();
203 204 205 206 207 208 209 210 211 212
        AlipayUserInfoShareRequest request = new AlipayUserInfoShareRequest();
        AlipayUserInfoShareResponse response = null;
        try {
            response = this.alipayClient.execute(request, accessToken);
        } catch (AlipayApiException e) {
            throw new AuthException(e.getErrMsg(), e);
        }
        if (!response.isSuccess()) {
            throw new AuthException(response.getSubMsg());
        }
智布道's avatar
智布道 已提交
213

不合群的混子's avatar
不合群的混子 已提交
214
        String province = response.getProvince(), city = response.getCity();
智布道's avatar
智布道 已提交
215 216
        String location = String.format("%s %s", StringUtils.isEmpty(province) ? "" : province, StringUtils.isEmpty(city) ? "" : city);

217
        return AuthUser.builder()
218
            .rawUserInfo(JSONObject.parseObject(JSONObject.toJSONString(response)))
不合群的混子's avatar
不合群的混子 已提交
219 220 221 222 223 224 225
            .uuid(response.getUserId())
            .username(StringUtils.isEmpty(response.getUserName()) ? response.getNickName() : response.getUserName())
            .nickname(response.getNickName())
            .avatar(response.getAvatar())
            .location(location)
            .gender(AuthUserGender.getRealGender(response.getGender()))
            .token(authToken)
226
            .source(source.toString())
不合群的混子's avatar
不合群的混子 已提交
227 228 229 230
            .build();
    }

    /**
231
     * 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
不合群的混子's avatar
不合群的混子 已提交
232
     *
233
     * @param state state 验证授权流程的参数,可以防止csrf
不合群的混子's avatar
不合群的混子 已提交
234
     * @return 返回授权地址
智布道's avatar
智布道 已提交
235
     * @since 1.9.3
不合群的混子's avatar
不合群的混子 已提交
236 237
     */
    @Override
238
    public String authorize(String state) {
不合群的混子's avatar
不合群的混子 已提交
239 240 241 242
        return UrlBuilder.fromBaseUrl(source.authorize())
            .queryParam("app_id", config.getClientId())
            .queryParam("scope", "auth_user")
            .queryParam("redirect_uri", config.getRedirectUri())
243
            .queryParam("state", getRealState(state))
不合群的混子's avatar
不合群的混子 已提交
244
            .build();
245 246
    }
}