All Downloads are FREE. Search and download functionalities are using the official Maven repository.

pjq.weibo.openapi.apis.WeiboApiOauth2 Maven / Gradle / Ivy

Go to download

基于微博开放平台官网的weibo4j-oauth2-beta3.1.1包及新版接口做二次开发

The newest version!
/*
 * Copyright © 2021 pengjianqiang
 * All rights reserved.
 * 项目名称:微博开放平台API-JAVA SDK
 * 项目描述:基于微博开放平台官网的weibo4j-oauth2-beta3.1.1包及新版接口做二次开发
 * 项目地址:https://github.com/qqxadyy/weibo-openapi-4java
 * 许可证信息:见下文
 *
 * ======================================================================
 *
 * The MIT License
 * Copyright © 2021 pengjianqiang
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package pjq.weibo.openapi.apis;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import pjq.commons.constant.CommonEnumConstant.TrueOrFalse;
import pjq.commons.utils.CharsetUtils;
import pjq.commons.utils.CheckUtils;
import pjq.commons.utils.DateTimeUtils;
import pjq.commons.utils.DefaultValueGetter;
import pjq.weibo.openapi.constant.ParamConstant.MoreUseParamNames;
import pjq.weibo.openapi.constant.ParamConstant.OAuth2Display;
import pjq.weibo.openapi.constant.ParamConstant.OAuth2Language;
import pjq.weibo.openapi.constant.ParamConstant.OAuth2Scope;
import pjq.weibo.openapi.constant.WeiboConfigs;
import pjq.weibo.openapi.support.WeiboApiParamScope;
import pjq.weibo.openapi.support.WeiboCacher;
import pjq.weibo.openapi.support.WeiboHttpClient.MethodType;
import weibo4j.Oauth;
import weibo4j.Weibo;
import weibo4j.model.AccessToken;
import weibo4j.model.AccessTokenInfo;
import weibo4j.model.PostParameter;
import weibo4j.model.User;
import weibo4j.model.WeiboException;

/**
 * oauth2相关接口
* 使用Weibo.of({@link WeiboApiOauth2}.class)生成对象 * * @author pengjianqiang * @date 2021年1月20日 */ @SuppressWarnings("serial") @Getter @Accessors(fluent = true) @NoArgsConstructor(access = AccessLevel.PRIVATE) @Slf4j public class WeiboApiOauth2 extends Weibo { private static Oauth apiOld = new Oauth(); /** * 申请scope权限所需参数,可一次申请多个scope权限,用逗号分隔 */ @WeiboApiParamScope(WeiboApiParamScope.OAUTH_BUILD_AUTHORIZE_URL) private OAuth2Scope[] scopes; /** * 是否使用state参数,true:是,false:否。默认true,并生成随机state值 */ @Setter(onMethod_ = {@WeiboApiParamScope(WeiboApiParamScope.OAUTH_BUILD_AUTHORIZE_URL)}) private TrueOrFalse useState; /** * 用于保持请求和回调的状态,在回调时,会在Query Parameter中回传该参数(useState为true时生效) */ @Setter(onMethod_ = {@WeiboApiParamScope(WeiboApiParamScope.OAUTH_BUILD_AUTHORIZE_URL)}) private String state; /** * 授权页面的终端类型 */ @Setter(onMethod_ = {@WeiboApiParamScope(WeiboApiParamScope.OAUTH_BUILD_AUTHORIZE_URL)}) private OAuth2Display display; /** * 是否强制用户重新登录,true:是,false:否。默认false */ @Setter(onMethod_ = {@WeiboApiParamScope(WeiboApiParamScope.OAUTH_BUILD_AUTHORIZE_URL)}) private TrueOrFalse forcelogin; /** * 授权页语言,缺省为中文简体版,en为英文版
* 英文版好像有问题,账号密码正确对会提示用扫码登录,建议不传该参数,默认用中文版 */ @Setter(onMethod_ = {@WeiboApiParamScope(WeiboApiParamScope.OAUTH_BUILD_AUTHORIZE_URL)}) private OAuth2Language language; @Override protected String checkAccessToken() { return null; // 该接口不用检查access_token } /** * 申请scope权限所需参数,可一次申请多个scope权限,用逗号分隔 * * @param scopes * @return */ @WeiboApiParamScope(WeiboApiParamScope.OAUTH_BUILD_AUTHORIZE_URL) public WeiboApiOauth2 scopes(OAuth2Scope... scopes) { this.scopes = scopes; return this; } /*----------------------------Oauth接口--------------------------------------*/ /** * 获取oahtu2-authorize接口的URL
* 为保证安全,获取授权URL时强制传state值 * * @return * @throws WeiboException */ public String apiBuildAuthorizeURL() throws WeiboException { StringBuilder url = new StringBuilder(); url.append(WeiboConfigs.getApiUrl(WeiboConfigs.OAUTH2_AUTHORIZE)); url.append("?").append(MoreUseParamNames.CLIENT_ID).append("=").append(clientId()); url.append("&").append(MoreUseParamNames.REDIRECT_URI).append("="); try { url.append(URLEncoder.encode(redirectURI(), CharsetUtils.UTF_8)); } catch (UnsupportedEncodingException e) { url.append(redirectURI()); } if (CheckUtils.isNotEmpty(scopes)) { String scopesStr = Arrays.stream(scopes) .collect(StringBuilder::new, (str, scope) -> str.append(scope.value()).append(","), (s1, s2) -> { }).toString(); url.append("&scope=").append(scopesStr.substring(0, scopesStr.length() - 1)); } // useState默认为true if (CheckUtils.isNull(useState)) { useState = TrueOrFalse.TRUE; } if (TrueOrFalse.TRUE.equals(useState)) { // 在传入的state基础上加上随机串,保证唯一 String genState = DefaultValueGetter.getValue("", state) + UUID.randomUUID().toString().replaceAll("-", ""); WeiboCacher.cacheStateInfoOfAuthorize(genState, clientId()); url.append("&").append(MoreUseParamNames.STATE).append("=").append(genState); } if (CheckUtils.isNotNull(display)) { url.append("&display=").append(display.value()); } if (CheckUtils.isNotNull(forcelogin)) { url.append("&forcelogin=").append(forcelogin.value()); } if (OAuth2Language.ENGLISH.equals(language)) { url.append("&language=").append(language.value()); // 只有指定英文时才传值 } return url.toString(); } /** * 获取授权过的AccessToken * * @param code * 授权回调后获取的code * @param state * 授权回调地址返回的state(该参数不是调接口需要的参数,而是用于安全验证) * @return * @throws WeiboException */ public AccessToken apiGetAccessTokenByCode(String code, String state) throws WeiboException { if (CheckUtils.isEmpty(code)) { throw WeiboException.ofParamCanNotNull(MoreUseParamNames.CODE); } // 先从缓存获取 AccessToken tokenInfo = WeiboCacher.getAccessTokenByCode(code); if (CheckUtils.isNotNull(tokenInfo)) { return tokenInfo; } if (CheckUtils.isNotEmpty(state)) { // 如果state不为空,则检查安全性 WeiboCacher.existsStateOfAuthorize(state); } tokenInfo = ((Oauth)apiOld.weiboConfiguration(weiboConfiguration())).getAccessTokenByCode(code); tokenInfo.setClientId(clientId()); tokenInfo.setCreateAt(DateTimeUtils.currentDateObj()); WeiboCacher.cacheAccessTokenOfCode(code, tokenInfo); return WeiboCacher.cacheAccessToken(tokenInfo); } /** * 用code换取到accessToken并通过该token获取到User信息 * * @param code * 授权回调后获取的code * @param state * 授权回调地址返回的state(该参数不是调接口需要的参数,而是用于安全验证) * @return * @throws WeiboException */ public User apiGetUserByCode(String code, String state) throws WeiboException { AccessToken accessToken = apiGetAccessTokenByCode(code, state); User user = null; try { user = Weibo.of(WeiboApiUsers.class, accessToken.getAccessToken(), weiboConfiguration()) .apiShowUserById(accessToken.getUid()); user.addAccessToken(accessToken); return WeiboCacher.cacheUser(user); } catch (Exception e) { // 如果已换取到token信息,但是查询授权用户信息失败,则先返回只带token信息的User对象,但不缓存(用于后续通过授权token重新查询用户信息) user = new User(); user.addAccessToken(accessToken); return user; } } /** * 查询用户access_token的授权相关信息 * * @param accessToken * 授权后的token * @return * @throws WeiboException */ public AccessToken apiGetTokenInfo(String accessToken) throws WeiboException { if (CheckUtils.isEmpty(accessToken)) { throw WeiboException.ofParamCanNotNull(MoreUseParamNames.ACCESS_TOKEN); } WeiboCacher.checkAccessTokenExists(accessToken); AccessTokenInfo tokenInfo = new AccessTokenInfo(client.post(WeiboConfigs.getApiUrl(WeiboConfigs.OAUTH2_GET_TOKEN_INFO), new PostParameter[] {new PostParameter(MoreUseParamNames.ACCESS_TOKEN, accessToken)}, false, null)); return tokenInfo.toAccessTokenObj(clientId(), accessToken); } /** * 查询用户access_token的授权相关信息并缓存
* 用于系统缓存中没有token详细信息而需要根据token值查询出并缓存的情况 * * @param accessToken * 授权后的token * @return * @throws WeiboException */ public AccessToken apiGetTokenInfoAndCache(String accessToken) throws WeiboException { if (CheckUtils.isEmpty(accessToken)) { throw WeiboException.ofParamCanNotNull(MoreUseParamNames.ACCESS_TOKEN); } AccessTokenInfo tokenInfo = new AccessTokenInfo(client.post(WeiboConfigs.getApiUrl(WeiboConfigs.OAUTH2_GET_TOKEN_INFO), new PostParameter[] {new PostParameter(MoreUseParamNames.ACCESS_TOKEN, accessToken)}, false, null)); return WeiboCacher.cacheAccessToken(tokenInfo.toAccessTokenObj(clientId(), accessToken)); } /** * 授权回收接口,帮助开发者主动取消用户的授权
* 注意:取消授权后再调用其它接口,会报错[21321:Applications over the unaudited use restrictions:未审核的应用使用人数超过限制],本地测试时尤其需要注意 * * @param accessToken * 授权后的token * @throws WeiboException */ public void apiRevokeOAuth2(String accessToken) throws WeiboException { if (CheckUtils.isEmpty(accessToken)) { throw WeiboException.ofParamCanNotNull(MoreUseParamNames.ACCESS_TOKEN); } try { // 实际是否成功取消授权都先移除缓存中的相关信息(移除前会检查缓存中有没有token信息) WeiboCacher.removeCachesByTokenWhenRevokeOAuth(accessToken); } catch (Exception e) { // 移除缓存时报错不影响后续发取消授权的请求 } // 异步发送取消授权的请求,不影响后续的业务流程 try { Map paramMap = new HashMap<>(); paramMap.put(MoreUseParamNames.ACCESS_TOKEN, accessToken); client.httpRequestAsync(WeiboConfigs.getApiUrl(WeiboConfigs.OAUTH2_REVOKE_OAUTH2), paramMap, MethodType.POST, false, null, (isSuccess, statusCode, responseStr) -> { log.info("取消微博授权结果[accessToken={},response={}]", accessToken, responseStr); }); } catch (Exception e) { } } /** * 取消授权回调
* 这个方法必须在收到取消授权回调请求的时候才能调用
* 考虑到安全问题,该方法不做实质处理 * * @param clientId * 应用clientid/appkey * @param uid * 取消授权的用户 * @param authEnd * 取消授权的时间 * @param verification * 应该是用于验证该请求是否微博发出参数,但是在官网没找到相关说明 */ public static void apiRevokeOAuth2Callback(String clientId, String uid, String authEnd, String verification) { // WeiboCacher.removeCachesByUidWhenRevokeOAuth(uid); // 收到取消授权的回调时再清除一次相关缓存,确保相关信息被移除 } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy