spring securityはWeChat登録を実現します.


紹介する
前の章ではQQで登録する方法を説明しました.今回の説明はWeChatで登録することです.
実装機能
WeChat登録を実現します.
開発ステップ
jarパッケージを導入する
jarパッケージの導入はQQに導入されたjarパッケージと一致しています.
ウィーチャットエンティティ情報
/**
 * @author lvhaibao
 * @description
 * @date 2019/1/4 0004 9:46
 */
@Data
public class WeixinUserInfo {

    /**
     *        ,          
     */
    private String openid;
    /**
     *       
     */
    private String nickname;
    /**
     *   
     */
    private String language;
    /**
     *       ,1   ,2   
     */
    private String sex;
    /**
     *              
     */
    private String province;
    /**
     *              
     */
    private String city;
    /**
     *   ,    CN
     */
    private String country;
    /**
     *     ,               ( 0、46、64、96、132    ,0  640*640     ),           
     */
    private String headimgurl;
    /**
     *       ,json  ,        (chinaunicom)
     */
    private String[] privilege;
    /**
     *       。                ,     unionid    。
     */
    private String unionid;
WeChatユーザーのアプリインターフェースと実装を取得する
/**
 * @author lvhaibao
 * @description
 * @date 2019/1/4 0004 9:49
 */
public interface Weixin {

    WeixinUserInfo getUserInfo(String openId);
}


/**
 * @author lvhaibao
 * @description
 * @date 2019/1/4 0004 9:50
 */
public class WeixinImpl  extends AbstractOAuth2ApiBinding implements Weixin  {

    /**
     *
     */
    private ObjectMapper objectMapper = new ObjectMapper();

    /**
     *        url
     */
    private static final String URL_GET_USER_INFO = "https://api.weixin.qq.com/sns/userinfo?openid=";


    /**
     * @param accessToken
     */
    public WeixinImpl(String accessToken) {
        super(accessToken, TokenStrategy.ACCESS_TOKEN_PARAMETER);
    }

    /**
     *      StringHttpMessageConverter    ISO-8859-1,       UTF-8 ,          。
     */
    @Override
    protected List> getMessageConverters() {
        List> messageConverters = super.getMessageConverters();
        messageConverters.remove(0);
        messageConverters.add(new StringHttpMessageConverter(Charset.forName("UTF-8")));
        return messageConverters;
    }

    /**
     *         。
     */
    @Override
    public WeixinUserInfo getUserInfo(String openId) {
        String url = URL_GET_USER_INFO + openId;
        String response = getRestTemplate().getForObject(url, String.class);
        if(StringUtils.contains(response, "errcode")) {
            return null;
        }
        WeixinUserInfo profile = null;
        try {
            profile = objectMapper.readValue(response, WeixinUserInfo.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return profile;
    }
}
Access Granntを書き換える
WeChatはQQとは違って、tokenを取得すると同時に、WeChatもopenIdに戻ります.ですから、Access Grantを書き換えます.
/**
 *    access_token  。   OAuth2    ,     access_token      openId,        accessToke  openId   
 *           AccessGrant,   openId  ,     access_token     。
 *
 * @author lvhaibao
 * @description
 * @date 2019/1/4 0004 9:53
 */
@Data
public class WeixinAccessGrant extends AccessGrant {

    private static final long serialVersionUID = -7243374526633186782L;

    private String openId;

    public WeixinAccessGrant() {
        super("");
    }

    public WeixinAccessGrant(String accessToken, String scope, String refreshToken, Long expiresIn) {
        super(accessToken, scope, refreshToken, expiresIn);
    }
}
OAuth 2 Templateを書き換える
/**
 * @author lvhaibao
 * @description   OAuth2Template
 * @date 2019/1/4 0004 10:00
 */
@Slf4j
public class WeixinOAuth2Template extends OAuth2Template {

    private String clientId;

    private String clientSecret;

    private String accessTokenUrl;

    private static final String REFRESH_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/refresh_token";

    public WeixinOAuth2Template(String clientId, String clientSecret, String authorizeUrl, String accessTokenUrl) {
        super(clientId, clientSecret, authorizeUrl, accessTokenUrl);
        setUseParametersForClientAuthentication(true);
        this.clientId = clientId;
        this.clientSecret = clientSecret;
        this.accessTokenUrl = accessTokenUrl;
    }

    /**
     *   access_token
     *
     * @param authorizationCode
     * @param redirectUri
     * @param parameters
     * @return
     */
    @Override
    public AccessGrant exchangeForAccess(String authorizationCode, String redirectUri,
                                         MultiValueMap parameters) {

        StringBuilder accessTokenRequestUrl = new StringBuilder(accessTokenUrl);

        accessTokenRequestUrl.append("?appid=" + clientId);
        accessTokenRequestUrl.append("&secret=" + clientSecret);
        accessTokenRequestUrl.append("&code=" + authorizationCode);
        accessTokenRequestUrl.append("&grant_type=authorization_code");
        accessTokenRequestUrl.append("&redirect_uri=" + redirectUri);

        return getAccessToken(accessTokenRequestUrl);
    }

    @Override
    public AccessGrant refreshAccess(String refreshToken, MultiValueMap additionalParameters) {

        StringBuilder refreshTokenUrl = new StringBuilder(REFRESH_TOKEN_URL);

        refreshTokenUrl.append("?appid=" + clientId);
        refreshTokenUrl.append("&grant_type=refresh_token");
        refreshTokenUrl.append("&refresh_token=" + refreshToken);

        return getAccessToken(refreshTokenUrl);
    }

    @SuppressWarnings("unchecked")
    private AccessGrant getAccessToken(StringBuilder accessTokenRequestUrl) {

        log.info("  access_token,   URL: " + accessTokenRequestUrl.toString());

        //    token
        String response = getRestTemplate().getForObject(accessTokenRequestUrl.toString(), String.class);

        log.info("  access_token,     : " + response);

        Map result = null;
        try {
            result = new ObjectMapper().readValue(response, Map.class);
        } catch (Exception e) {
            e.printStackTrace();
        }

        //           
        if (StringUtils.isNotBlank(MapUtils.getString(result, "errcode"))) {
            String errcode = MapUtils.getString(result, "errcode");
            String errmsg = MapUtils.getString(result, "errmsg");
            throw new RuntimeException("  access token  , errcode:" + errcode + ", errmsg:" + errmsg);
        }

        //  token   ,   openid,  
        WeixinAccessGrant accessToken = new WeixinAccessGrant(
                MapUtils.getString(result, "access_token"),
                MapUtils.getString(result, "scope"),
                MapUtils.getString(result, "refresh_token"),
                MapUtils.getLong(result, "expires_in"));

        accessToken.setOpenId(MapUtils.getString(result, "openid"));

        return accessToken;
    }

    /**
     *           。               。
     */
    @Override
    public String buildAuthenticateUrl(OAuth2Parameters parameters) {
        String url = super.buildAuthenticateUrl(parameters);
        url = url + "&appid=" + clientId + "&scope=snsapi_login";
        return url;
    }

    @Override
    public String buildAuthorizeUrl(OAuth2Parameters parameters) {
        return buildAuthenticateUrl(parameters);
    }

    /**
     *      contentType html/text,     HttpMessageConverter   。
     */
    @Override
    protected RestTemplate createRestTemplate() {
        RestTemplate restTemplate = super.createRestTemplate();
        restTemplate.getMessageConverters().add(new StringHttpMessageConverter(Charset.forName("UTF-8")));
        return restTemplate;
    }
}
自分のWeixin ServiceProviderを作成します.
/**
 *    OAuth2         , spring social connect    
 *
 * @author lvhaibao
 * @description
 * @date 2019/1/4 0004 10:02
 */
public class WeixinServiceProvider extends AbstractOAuth2ServiceProvider {

    /**
     *         url
     */
    private static final String URL_AUTHORIZE = "https://open.weixin.qq.com/connect/qrconnect";
    /**
     *     accessToken url
     */
    private static final String URL_ACCESS_TOKEN = "https://api.weixin.qq.com/sns/oauth2/access_token";

    /**
     * @param appId
     * @param appSecret
     */
    public WeixinServiceProvider(String appId, String appSecret) {
        super(new WeixinOAuth2Template(appId, appSecret,URL_AUTHORIZE,URL_ACCESS_TOKEN));
    }


    @Override
    public Weixin getApi(String accessToken) {
        return new WeixinImpl(accessToken);
    }
}
自分のWeixinAdapterを作成します.
/**
 *    api   ,    api       spring social     。
 *
 * @author lvhaibao
 * @description
 * @date 2019/1/4 0004 9:56
 */
public class WeixinAdapter implements ApiAdapter {

    private String openId;

    public WeixinAdapter() {}

    public WeixinAdapter(String openId){
        this.openId = openId;
    }
    /**
     * @param api
     * @return
     */
    @Override
    public boolean test(Weixin api) {
        return true;
    }

    /**
     * @param api
     * @param values
     */
    @Override
    public void setConnectionValues(Weixin api, ConnectionValues values) {
        WeixinUserInfo profile = api.getUserInfo(openId);
        values.setProviderUserId(profile.getOpenid());
        values.setDisplayName(profile.getNickname());
        values.setImageUrl(profile.getHeadimgurl());
    }

    /**
     * @param api
     * @return
     */
    @Override
    public UserProfile fetchUserProfile(Weixin api) {
        return null;
    }

    /**
     * @param api
     * @param message
     */
    @Override
    public void updateStatus(Weixin api, String message) {
        //do nothing
    }
}
WeChat接続工場Connection Factory
/**
 * @author lvhaibao
 * @description       
 * @date 2019/1/4 0004 9:59
 */
public class WeixinConnectionFactory extends OAuth2ConnectionFactory {

    /**
     * @param appId
     * @param appSecret
     */
    public WeixinConnectionFactory(String providerId, String appId, String appSecret) {
        super(providerId, new WeixinServiceProvider(appId, appSecret), new WeixinAdapter());
    }

    /**
     *      openId  accessToken     ,         accessToken  providerUserId  ,   QQ    QQAdapter   
     */
    @Override
    protected String extractProviderUserId(AccessGrant accessGrant) {
        if (accessGrant instanceof WeixinAccessGrant) {
            return ((WeixinAccessGrant) accessGrant).getOpenId();
        }
        return null;
    }

    @Override
    public Connection createConnection(AccessGrant accessGrant) {
        return new OAuth2Connection(getProviderId(), extractProviderUserId(accessGrant), accessGrant.getAccessToken(),
                accessGrant.getRefreshToken(), accessGrant.getExpireTime(), getOAuth2ServiceProvider(), getApiAdapter(extractProviderUserId(accessGrant)));
    }

    @Override
    public Connection createConnection(ConnectionData data) {
        return new OAuth2Connection(data, getOAuth2ServiceProvider(), getApiAdapter(data.getProviderUserId()));
    }

    private ApiAdapter getApiAdapter(String providerUserId) {
        return new WeixinAdapter(providerUserId);
    }

    private OAuth2ServiceProvider getOAuth2ServiceProvider() {
        return (OAuth2ServiceProvider) getServiceProvider();
    }
}
カスタマイズWeChatのサービスプロバイダId
/**
 * @author lvhaibao
 * @description            ID
 * @date 2019/1/4 0004 9:47
 */
@Data
public class WeixinProperties extends SocialProperties {

    private String providerId = "weixin";

}

プロファイルの作成
system:
#     
  social:
    filterProcessesUrl: /qqLogin
    weixin:
      app-id: wx8a47a66e22296c62
      app-secret: deb57af7ec1753a2668889e74b34b789
ページ
ページにこのリンクを追加すればいいです.
WeChat  
他の配置も前の章に書いてあります.読者は自らプロジェクトのソースコードを調べたり、調べたりすることができます.
テスト
QQ登録と同じです.ここでは述べるのをやめます.
プロジェクトのソースコード
https://gitee.com/lvhaibao/spring-lhbauth/tree/42327d841a8d606bf5b5167c7ecabe72040ec735/