com.dahuatech.icc.oauth.handle.TokenHandlerProcessor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of java-sdk-oauth Show documentation
Show all versions of java-sdk-oauth Show documentation
Dahua ICC Open API SDK for Java
package com.dahuatech.icc.oauth.handle;
import com.dahuatech.hutool.core.thread.NamedThreadFactory;
import com.dahuatech.hutool.core.util.StrUtil;
import com.dahuatech.hutool.json.JSONObject;
import com.dahuatech.hutool.json.JSONUtil;
import com.dahuatech.hutool.log.Log;
import com.dahuatech.hutool.log.LogFactory;
import com.dahuatech.icc.common.ErrorConstants;
import com.dahuatech.icc.exception.ClientException;
import com.dahuatech.icc.oauth.constant.OauthConstant;
import com.dahuatech.icc.oauth.http.IccTokenResponse;
import com.dahuatech.icc.oauth.model.v202010.*;
import com.dahuatech.icc.oauth.profile.GrantType;
import com.dahuatech.icc.oauth.profile.IccProfile;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
/**
* 单例,获取access_token,刷新access_token,登录状态保活
*
* @author 232676
* @since 1.0.0 2020-10-24 20:59:11
*/
public class TokenHandlerProcessor {
private static final Log logger = LogFactory.get();
/** access_token 首次获取状态 */
private static final AtomicBoolean TOKEN_INITED = new AtomicBoolean(Boolean.FALSE);
/** token刷新间隔 30s */
private static final long FRESH_TOKEN_INTERVAL = 30 * 1000;
/** 线程刷新token和保活 */
private final ScheduledExecutorService REFRESH_TOKEN_SCHEDULED =
newSingleThreadScheduledExecutor(new NamedThreadFactory("Icc-Refresh-Token-New", true));
/** 密码和客户端认证存储Map */
private final Map tokenMap = new ConcurrentHashMap<>();
private final Map httpConfigMap = new ConcurrentHashMap<>();
public Map getTokenMap() {
return tokenMap;
}
/** 定时任务刷新token */
private TokenHandlerProcessor() {
REFRESH_TOKEN_SCHEDULED.scheduleWithFixedDelay(
new Runnable() {
@Override
public void run() {
try {
refreshTokenAndKeepAlive();
} catch (Throwable t) { // Defensive fault tolerance
logger.error("Unexpected error occur at token refresh, cause: " + t.getMessage(), t);
}
}
},
FRESH_TOKEN_INTERVAL,
FRESH_TOKEN_INTERVAL,
TimeUnit.MILLISECONDS);
}
/**
* 获取Token处理器实例
*
* @return Token处理器实例
*/
public static synchronized TokenHandlerProcessor getInstance() {
return SingletonHolder.INSTANCE;
}
/**
* 根据配置信息获取ICC令牌
*
* @param oauthConfigBaseInfo 配置信息
* @return ICC令牌
*/
public synchronized IccTokenResponse.IccToken oauth(OauthConfigBaseInfo oauthConfigBaseInfo) {
IccTokenResponse.IccToken token = null;
try {
token = OauthProcessor.getIntance().oauth(oauthConfigBaseInfo);
httpConfigMap.put(getKey(oauthConfigBaseInfo), oauthConfigBaseInfo);//保存用户信息用于异常情况,重新获取token
tokenMap.put(getKey(oauthConfigBaseInfo), token);//保存token用于刷新token
} catch (ClientException e) {
logger.error("get token failure");
}
return token;
}
/**
* 从缓存获取token
*
* @param oauthConfigBaseInfo 用户配置信息
* @return IccTokenResponse.IccToken
*/
public IccTokenResponse.IccToken getTokenCache(OauthConfigBaseInfo oauthConfigBaseInfo) {
if(REFRESH_TOKEN_SCHEDULED.isShutdown() || REFRESH_TOKEN_SCHEDULED.isTerminated()){
logger.warn("定时任务进程异常关闭,重新加载");
REFRESH_TOKEN_SCHEDULED.scheduleWithFixedDelay(
new Runnable() {
@Override
public void run() {
try {
refreshTokenAndKeepAlive();
} catch (Throwable t) { // Defensive fault tolerance
logger.error("Unexpected error occur at token refresh, cause: " + t.getMessage(), t);
}
}
},
FRESH_TOKEN_INTERVAL,
FRESH_TOKEN_INTERVAL,
TimeUnit.MILLISECONDS);
}
String key = getKey(oauthConfigBaseInfo);
IccTokenResponse.IccToken token = tokenMap.get(key);
Long currentTime = System.currentTimeMillis();
if(token != null && token.getTtl() < currentTime){//说明token过期了
logger.warn("[{}]的token已过期,清理token信息:{}",key, JSONUtil.toJsonStr(token));
clearExpiredToken(oauthConfigBaseInfo);
return null;
}
return tokenMap.get(key);
}
/**
* 刷新token 并缓存
*
* @param key 授权类型
* @param refreshToken 刷新fresh_token
* @return IccTokenResponse.IccToken
*/
public IccTokenResponse.IccToken refreshToken(String key, String refreshToken) {
OauthConfigBaseInfo oauthConfigBaseInfo = httpConfigMap.get(key);
try {
if(oauthConfigBaseInfo.getGrantType() == GrantType.password){//用户密码模式刷新token
OauthRefreshTokenResponse refreshTokenResponse = OauthProcessor.getIntance().refreshToken(oauthConfigBaseInfo,refreshToken);
if (refreshTokenResponse.isSuccess()) {
OauthRefreshTokenResponse.IccReFreshToken freshToken = refreshTokenResponse.getData();
IccTokenResponse.IccToken iccToken = new IccTokenResponse.IccToken();
iccToken.setTtl(System.currentTimeMillis() + (freshToken.getExpires_in() * 1000));
iccToken.setAccess_token(freshToken.getAccess_token());
iccToken.setExpires_in(freshToken.getExpires_in());
iccToken.setMagicId(freshToken.getMagicId());
iccToken.setUserId(freshToken.getUserId());
iccToken.setToken_type(freshToken.getToken_type());
iccToken.setRefresh_token(freshToken.getRefresh_token());
iccToken.setScope(freshToken.getScope());
tokenMap.put(getKey(oauthConfigBaseInfo),iccToken);//保存token用于刷新token
return iccToken;
}else{
return oauth(oauthConfigBaseInfo);
}
}else if(oauthConfigBaseInfo.getGrantType() == GrantType.client_credentials){
IccTokenResponse.IccToken refreshTokenResponse = OauthProcessor.getIntance().oauth(oauthConfigBaseInfo);
tokenMap.put(getKey(oauthConfigBaseInfo),refreshTokenResponse);//保存token用于刷新token
return refreshTokenResponse;
}
} catch (ClientException e) {
logger.error(
"fresh token error , grantType=[{}],freshToken=[{}]", oauthConfigBaseInfo.getGrantType().name(), refreshToken);
}
return null;
}
/**
* 定期刷新和保持token有效性
*/
private void refreshTokenAndKeepAlive() {
for (Map.Entry entry : tokenMap.entrySet()) {
IccTokenResponse.IccToken token = entry.getValue();
Long currentTime = System.currentTimeMillis();
/** 如果时间还剩120s,则刷新token */
if (token.getTtl() - currentTime <= 120 * 1000) {
refreshToken(entry.getKey(), token.getRefresh_token());
}
keepalive(entry.getKey());
}
}
/** 保活接口 */
private void keepalive(String key) {
OauthConfigBaseInfo oauthConfigBaseInfo = httpConfigMap.get(key);
IccTokenResponse.IccToken token = tokenMap.get(key);
try {
BrmKeepAliveResponse brmKeepAliveResponse = OauthProcessor.getIntance().keepAlive(oauthConfigBaseInfo,token.getMagicId(), OauthConstant.ClientType.WEB);
if(!brmKeepAliveResponse.isSuccess() && ErrorConstants.OAUTH_INVALID_TOKEN.equalsIgnoreCase(
brmKeepAliveResponse.getCode())){
oauth(oauthConfigBaseInfo);
}
} catch (Exception e) {
e.printStackTrace();
try{
oauth(oauthConfigBaseInfo);
}catch (Exception retryE){
logger.error("keepalive retry error,key:" + key,e);
};
}
}
/**
* 根据授权类型获取授权密钥名称
*
* @param grantType 授权类型
* @return 授权密钥名称
*/
private String enGrantKeyName(String grantType) {
return grantType + StrUtil.COLON + IccProfile.host;
}
/**
* 根据授权密钥名称获取授权类型
*
* @param grantKeyName 授权密钥名称
* @return 授权类型
*/
private GrantType deGrantType(String grantKeyName) {
return GrantType.valueOf(grantKeyName.substring(0, grantKeyName.indexOf(StrUtil.COLON)));
}
/**
* 清除过期的token
*
* @param oauthConfigBaseInfo
*/
public void clearExpiredToken(OauthConfigBaseInfo oauthConfigBaseInfo) {
tokenMap.remove(getKey(oauthConfigBaseInfo));
httpConfigMap.remove(getKey(oauthConfigBaseInfo));
}
private static class SingletonHolder {
private static final TokenHandlerProcessor INSTANCE = new TokenHandlerProcessor();
}
/**
* key 格式
* @param oauthConfigBaseInfo
* @return
*/
private String getKey(OauthConfigBaseInfo oauthConfigBaseInfo){
String host = oauthConfigBaseInfo.getHttpConfigInfo().getHost();
String port = oauthConfigBaseInfo.getHttpConfigInfo().isEnableHttpTest()? oauthConfigBaseInfo.getHttpConfigInfo().getHttpPort():oauthConfigBaseInfo.getHttpConfigInfo().getHttpsPort();
String grantType = oauthConfigBaseInfo.getGrantType().name();
String userName = null;
if(oauthConfigBaseInfo.getGrantType() == GrantType.password){
OauthConfigUserPwdInfo oauthConfigUserPwdInfo = (OauthConfigUserPwdInfo)oauthConfigBaseInfo;
userName = oauthConfigUserPwdInfo.getUsername();
}else{
OauthConfigClientInfo oauthConfigClientInfo = (OauthConfigClientInfo)oauthConfigBaseInfo;
userName = oauthConfigClientInfo.getClientOauthuserId();
}
return host + "_" + port + "_" + grantType + "_" + userName;
}
}