AuthWeChatRequest.java 5.3 KB
Newer Older
1 2 3 4 5 6
package me.zhyd.oauth.request;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson.JSONObject;
import me.zhyd.oauth.config.AuthConfig;
7
import me.zhyd.oauth.config.AuthSource;
智布道's avatar
智布道 已提交
8
import me.zhyd.oauth.enums.AuthUserGender;
9
import me.zhyd.oauth.exception.AuthException;
10
import me.zhyd.oauth.model.*;
不合群的混子's avatar
不合群的混子 已提交
11
import me.zhyd.oauth.utils.UrlBuilder;
12 13 14 15

/**
 * 微信登录
 *
智布道's avatar
智布道 已提交
16
 * @author yangkai.shen (https://xkcoding.com)
智布道's avatar
智布道 已提交
17
 * @since 1.1.0
18
 */
智布道's avatar
智布道 已提交
19
public class AuthWeChatRequest extends AuthDefaultRequest {
20
    public AuthWeChatRequest(AuthConfig config) {
不合群的混子's avatar
不合群的混子 已提交
21
        super(config, AuthSource.WECHAT);
22 23 24 25 26
    }

    /**
     * 微信的特殊性,此时返回的信息同时包含 openid 和 access_token
     *
智布道's avatar
智布道 已提交
27
     * @param authCallback 回调返回的参数
28 29 30
     * @return 所有信息
     */
    @Override
31
    protected AuthToken getAccessToken(AuthCallback authCallback) {
不合群的混子's avatar
不合群的混子 已提交
32
        return this.getToken(accessTokenUrl(authCallback.getCode()));
33 34 35
    }

    @Override
智布道's avatar
智布道 已提交
36 37
    protected AuthUser getUserInfo(AuthToken authToken) {
        String openId = authToken.getOpenId();
38

不合群的混子's avatar
不合群的混子 已提交
39
        HttpResponse response = doGetUserInfo(authToken);
40
        JSONObject object = JSONObject.parseObject(response.body());
41 42

        this.checkResponse(object);
43

智布道's avatar
智布道 已提交
44
        String location = String.format("%s-%s-%s", object.getString("country"), object.getString("province"), object.getString("city"));
45

不合群的混子's avatar
不合群的混子 已提交
46
        if (object.containsKey("unionid")) {
47 48 49
            authToken.setUnionId(object.getString("unionid"));
        }

50
        return AuthUser.builder()
不合群的混子's avatar
不合群的混子 已提交
51 52 53 54 55 56 57
            .username(object.getString("nickname"))
            .nickname(object.getString("nickname"))
            .avatar(object.getString("headimgurl"))
            .location(location)
            .uuid(openId)
            .gender(AuthUserGender.getRealGender(object.getString("sex")))
            .token(authToken)
58
            .source(source)
不合群的混子's avatar
不合群的混子 已提交
59
            .build();
60 61 62
    }

    @Override
63 64
    public AuthResponse refresh(AuthToken oldToken) {
        return AuthResponse.builder()
不合群的混子's avatar
不合群的混子 已提交
65 66 67
            .code(AuthResponseStatus.SUCCESS.getCode())
            .data(this.getToken(refreshTokenUrl(oldToken.getRefreshToken())))
            .build();
68
    }
69

70 71 72 73 74 75
    /**
     * 检查响应内容是否正确
     *
     * @param object 请求响应内容
     */
    private void checkResponse(JSONObject object) {
76
        if (object.containsKey("errcode")) {
77
            throw new AuthException(object.getIntValue("errcode"), object.getString("errmsg"));
78
        }
79
    }
智布道's avatar
智布道 已提交
80

81 82 83 84 85 86 87 88
    /**
     * 获取token,适用于获取access_token和刷新token
     *
     * @param accessTokenUrl 实际请求token的地址
     * @return token对象
     */
    private AuthToken getToken(String accessTokenUrl) {
        HttpResponse response = HttpRequest.get(accessTokenUrl).execute();
智布道's avatar
智布道 已提交
89
        JSONObject accessTokenObject = JSONObject.parseObject(response.body());
90

智布道's avatar
智布道 已提交
91
        this.checkResponse(accessTokenObject);
92

93
        return AuthToken.builder()
不合群的混子's avatar
不合群的混子 已提交
94 95 96 97 98 99 100 101
            .accessToken(accessTokenObject.getString("access_token"))
            .refreshToken(accessTokenObject.getString("refresh_token"))
            .expireIn(accessTokenObject.getIntValue("expires_in"))
            .openId(accessTokenObject.getString("openid"))
            .build();
    }

    /**
102
     * 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
不合群的混子's avatar
不合群的混子 已提交
103
     *
104
     * @param state state 验证授权流程的参数,可以防止csrf
不合群的混子's avatar
不合群的混子 已提交
105
     * @return 返回授权地址
智布道's avatar
智布道 已提交
106
     * @since 1.9.3
不合群的混子's avatar
不合群的混子 已提交
107 108
     */
    @Override
109
    public String authorize(String state) {
不合群的混子's avatar
不合群的混子 已提交
110 111 112 113 114
        return UrlBuilder.fromBaseUrl(source.authorize())
            .queryParam("response_type", "code")
            .queryParam("appid", config.getClientId())
            .queryParam("redirect_uri", config.getRedirectUri())
            .queryParam("scope", "snsapi_login")
115
            .queryParam("state", getRealState(state))
不合群的混子's avatar
不合群的混子 已提交
116 117 118 119 120 121
            .build();
    }

    /**
     * 返回获取accessToken的url
     *
智布道's avatar
智布道 已提交
122
     * @param code 授权码
不合群的混子's avatar
不合群的混子 已提交
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
     * @return 返回获取accessToken的url
     */
    @Override
    protected String accessTokenUrl(String code) {
        return UrlBuilder.fromBaseUrl(source.accessToken())
            .queryParam("code", code)
            .queryParam("appid", config.getClientId())
            .queryParam("secret", config.getClientSecret())
            .queryParam("grant_type", "authorization_code")
            .build();
    }

    /**
     * 返回获取userInfo的url
     *
智布道's avatar
智布道 已提交
138
     * @param authToken 用户授权后的token
不合群的混子's avatar
不合群的混子 已提交
139 140 141 142 143 144 145 146 147 148 149 150
     * @return 返回获取userInfo的url
     */
    @Override
    protected String userInfoUrl(AuthToken authToken) {
        return UrlBuilder.fromBaseUrl(source.userInfo())
            .queryParam("access_token", authToken.getAccessToken())
            .queryParam("openid", authToken.getOpenId())
            .queryParam("lang", "zh_CN")
            .build();
    }

    /**
智布道's avatar
智布道 已提交
151
     * 返回获取userInfo的url
不合群的混子's avatar
不合群的混子 已提交
152
     *
智布道's avatar
智布道 已提交
153 154
     * @param refreshToken getAccessToken方法返回的refreshToken
     * @return 返回获取userInfo的url
不合群的混子's avatar
不合群的混子 已提交
155 156 157 158 159 160 161 162
     */
    @Override
    protected String refreshTokenUrl(String refreshToken) {
        return UrlBuilder.fromBaseUrl(source.refresh())
            .queryParam("appid", config.getClientId())
            .queryParam("refresh_token", refreshToken)
            .queryParam("grant_type", "refresh_token")
            .build();
163 164
    }
}