提交 6470b2b0 编写于 作者: zhouweidong's avatar zhouweidong

token缓存改造

上级 15f21e6a
......@@ -120,6 +120,7 @@ public class DevBootSecurityConfig extends WebSecurityConfigurerAdapter {
.antMatchers("/uaa/queryQQUserByCode").permitAll()
.antMatchers("/uaa/bindQQtoRegister").permitAll()
.antMatchers("/uaa/publickey").permitAll()
.antMatchers("/uaa/dingtalk/jsapi/sign").permitAll()
.anyRequest().authenticated()
// 防止iframe 造成跨域
.and().headers().frameOptions().disable();
......
package cn.ibizlab.core.uaa.extensions.helper;
import cn.ibizlab.util.errors.BadRequestAlertException;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.request.OapiGetJsapiTicketRequest;
import com.dingtalk.api.request.OapiGettokenRequest;
import com.dingtalk.api.response.OapiGetJsapiTicketResponse;
import com.dingtalk.api.response.OapiGettokenResponse;
import lombok.SneakyThrows;
import org.springframework.util.StringUtils;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Formatter;
public class DingTalkHelper {
/**
* 获取jsapi_ticket
* @param accessToken
* @return
*/
@SneakyThrows
public static String getJsapiTicket(String accessToken){
DefaultDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/get_jsapi_ticket");
OapiGetJsapiTicketRequest req = new OapiGetJsapiTicketRequest();
req.setTopHttpMethod("GET");
OapiGetJsapiTicketResponse execute = client.execute(req, accessToken);
return execute.getTicket();
}
/**
* 计算签名
* @param ticket
* @param nonceStr
* @param timeStamp
* @param url
* @return
*/
public static String sign(String ticket, String nonceStr, long timeStamp, String url){
String plain = "jsapi_ticket=" + ticket + "&noncestr=" + nonceStr + "&timestamp=" + String.valueOf(timeStamp)
+ "&url=" + url;
try {
MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
sha1.reset();
sha1.update(plain.getBytes("UTF-8"));
return byteToHex(sha1.digest());
} catch (NoSuchAlgorithmException e) {
throw new BadRequestAlertException(e.getMessage(),"sign","");
} catch (UnsupportedEncodingException e) {
throw new BadRequestAlertException(e.getMessage(),"sign","");
}
}
// 字节数组转化成十六进制字符串
private static String byteToHex(final byte[] hash) {
Formatter formatter = new Formatter();
for (byte b : hash) {
formatter.format("%02x", b);
}
String result = formatter.toString();
formatter.close();
return result;
}
/**
* 获取token
* @param appKey
* @param appSecret
* @return
*/
@SneakyThrows
public static String getAccessToken(String appKey,String appSecret){
DefaultDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/gettoken");
OapiGettokenRequest request = new OapiGettokenRequest();
request.setAppkey(appKey);
request.setAppsecret(appSecret);
request.setHttpMethod("GET");
OapiGettokenResponse response = client.execute(request);
if (response.getErrcode() != 0 || StringUtils.isEmpty(response.getAccessToken()))
throw new BadRequestAlertException("获取access_token失败", "UserDingtalkRegisterService", response.getErrmsg());
return response.getAccessToken();
}
}
package cn.ibizlab.core.uaa.extensions.service;
import cn.ibizlab.core.uaa.extensions.helper.DingTalkHelper;
import cn.ibizlab.util.domain.TokenInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
@Service
@Slf4j
public class DingTalkTokenService {
@Autowired
@Lazy
DingTalkTokenService proxyService;
/**
* 通过api获取token及ticket并缓存
* @param appKey
* @param appSecret
* @return
*/
@Cacheable(value="accesstoken",key = "'appid:'+#p0+'||'+#p1")
public TokenInfo getTokenInfoByCache(String appKey, String appSecret){
String ticket = null;
String token =DingTalkHelper.getAccessToken(appKey,appSecret);
if(!StringUtils.isEmpty(token)){
ticket=DingTalkHelper.getJsapiTicket(token);
}
return TokenInfo.builder().accessToken(token).lastRefreshTime(System.currentTimeMillis()).ticket(ticket).build();
}
/**
* 清除token.ticket缓存
* @param appKey
* @param appSecret
*/
@CacheEvict( value="accesstoken",key = "'appid:'+#p0+'||'+#p1")
public void resetToken(String appKey,String appSecret){
}
/**
* 获取token
* @param appKey
* @param appSecret
* @return
*/
public String getAccessToken(String appKey,String appSecret){
String token="";
TokenInfo tokenInfo=proxyService.getTokenInfo(appKey, appSecret);
if(!ObjectUtils.isEmpty(tokenInfo)){
return tokenInfo.getAccessToken();
}
return token;
}
/**
* 获取ticket
* @param appKey
* @param appSecret
* @return
*/
public String getJSTicket(String appKey,String appSecret){
String ticket="";
TokenInfo tokenInfo=proxyService.getTokenInfo(appKey, appSecret);
if(!ObjectUtils.isEmpty(tokenInfo)){
return tokenInfo.getTicket();
}
return ticket;
}
/**
* 获取token信息
* @param appKey
* @param appSecret
* @return
*/
public synchronized TokenInfo getTokenInfo(String appKey,String appSecret){
TokenInfo tokenInfo = proxyService.getTokenInfoByCache(appKey,appSecret);
if(!ObjectUtils.isEmpty(tokenInfo)){
if (System.currentTimeMillis() < tokenInfo.getLastRefreshTime() + 7100000) {//缓存是否过期
return tokenInfo;
}
else{
proxyService.resetToken(appKey,appSecret);//清除缓存
return proxyService.getTokenInfoByCache(appKey,appSecret);//重新进缓存
}
}
return null;
}
}
......@@ -4,11 +4,14 @@ package cn.ibizlab.core.uaa.extensions.service;
import cn.ibizlab.core.uaa.domain.*;
import cn.ibizlab.core.uaa.extensions.domain.PermissionNode;
import cn.ibizlab.core.uaa.extensions.domain.PermissionType;
import cn.ibizlab.core.uaa.extensions.helper.DingTalkHelper;
import cn.ibizlab.core.uaa.filter.SysRolePermissionSearchContext;
import cn.ibizlab.core.uaa.service.ISysPSSystemService;
import cn.ibizlab.core.uaa.service.ISysRolePermissionService;
import cn.ibizlab.core.uaa.service.ISysRoleService;
import cn.ibizlab.core.uaa.service.ISysUserRoleService;
import cn.ibizlab.util.errors.BadRequestAlertException;
import com.alibaba.fastjson.JSONObject;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
......@@ -20,16 +23,18 @@ import org.springframework.context.annotation.Lazy;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Service;
import org.springframework.util.AlternativeJdkIdGenerator;
import org.springframework.util.Base64Utils;
import org.springframework.util.ObjectUtils;
import java.io.*;
import org.springframework.util.StringUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.*;
@Service
......@@ -52,6 +57,14 @@ public class UAACoreService {
@Lazy
private ISysRoleService sysRoleService;
@Autowired
@Lazy
private UserDingtalkRegisterService userDingtalkRegisterService;
@Autowired
@Lazy
private DingTalkTokenService dingTalkTokenService;
public Map<String,List<PermissionNode>> getPermissionTree()
{
List<PermissionNode> apps = new ArrayList<>();
......@@ -290,6 +303,31 @@ public class UAACoreService {
return key;
}
/**
* 获取钉钉jsApi签名
* @param openAccessId
* @return
*/
public JSONObject getDingTalkJSSign(String openAccessId,String url){
JSONObject sign=new JSONObject();
SysOpenAccess openAccess = userDingtalkRegisterService.getOpenAccess(openAccessId);
if (openAccess==null || (openAccess.getDisabled()!=null && openAccess.getDisabled()==1))
throw new BadRequestAlertException("未找到配置", "UAACoreService", "getOpenAccess");
String ticket=dingTalkTokenService.getJSTicket(openAccess.getAccessKey(),openAccess.getSecretKey());
if(StringUtils.isEmpty(ticket)){
throw new BadRequestAlertException("获取ticket失败","UAACoreService","getJSTicket");
}
String nonceStr=(new AlternativeJdkIdGenerator()).generateId().toString().replace("-", "");
Long timeStamp=System.currentTimeMillis();
String strSign = DingTalkHelper.sign(ticket, nonceStr,timeStamp , url);
sign.put("url",url);
sign.put("nonceStr",nonceStr);
sign.put("agentId",openAccess.getAccessKey());
sign.put("timeStamp",timeStamp);
sign.put("corpId",openAccess.getRegionId());
sign.put("signature",strSign);
return sign;
}
}
......@@ -11,36 +11,20 @@ import cn.ibizlab.util.security.AuthenticationUser;
import cn.ibizlab.util.service.AuthenticationUserService;
import cn.ibizlab.util.service.IBZUSERService;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.client.identify.Base64;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.*;
import com.dingtalk.api.response.*;
import com.dingtalk.api.request.OapiSnsGetuserinfoBycodeRequest;
import com.dingtalk.api.request.OapiUserGetuserinfoRequest;
import com.dingtalk.api.response.OapiSnsGetuserinfoBycodeResponse;
import com.dingtalk.api.response.OapiUserGetuserinfoResponse;
import com.taobao.api.ApiException;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.sql.Timestamp;
import java.sql.Wrapper;
import java.util.*;
/**
* 实体[IBZUSER] 钉钉用户注册接口实现
*/
......@@ -57,42 +41,9 @@ public class UserDingtalkRegisterService {
@Autowired
private ISysUserAuthService sysUserAuthService;
// private long lastRefreshTime=System.currentTimeMillis()-7200001;
// private String accessToken="";
// public boolean isExpire()
// {
// if(System.currentTimeMillis()<(lastRefreshTime+7200000))
// {
// System.currentTimeMillis();
// return false;
// }
// return true;
// }
public synchronized String getAccessToken(String appKey,String appSecret)
{
if (isExpire(appKey)) {
DefaultDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/gettoken");
OapiGettokenRequest request = new OapiGettokenRequest();
request.setAppkey(appKey);
request.setAppsecret(appSecret);
request.setHttpMethod("GET");
try {
OapiGettokenResponse response = client.execute(request);
if (response.getErrcode() != 0 || StringUtils.isEmpty(response.getAccessToken()))
throw new BadRequestAlertException("获取access_token失败", "UserDingtalkRegisterService", response.getErrmsg());
// lastRefreshTime = System.currentTimeMillis();
// accessToken = response.getAccessToken();
setTokenInfo(appKey, response.getAccessToken(), System.currentTimeMillis());
} catch (ApiException e) {
e.printStackTrace();
throw new InternalServerErrorException("获取access_token失败");
}
}
return getToken(appKey);
}
@Autowired
@Lazy
DingTalkTokenService dingTalkTokenService;
@Autowired
private ISysOpenAccessService sysOpenAccessService;
......@@ -110,24 +61,9 @@ public class UserDingtalkRegisterService {
if((sysOpenAccess==null|| (sysOpenAccess.getDisabled()!=null && sysOpenAccess.getDisabled()==1))&&throwEx)
throw new BadRequestAlertException("获取接入配置失败","UserDingtalkRegisterService","");
try {
// 可能抛出异常,但暂时不进行处理
String accessToken = getAccessToken(sysOpenAccess.getAccessKey(),sysOpenAccess.getSecretKey());
if(!accessToken.equals(sysOpenAccess.getAccessToken()))
{
sysOpenAccess.setAccessToken(accessToken);
sysOpenAccess.setExpiresTime(new Timestamp(getLastRefreshTime(sysOpenAccess.getAccessKey())));
sysOpenAccessService.update(sysOpenAccess);
}
}catch (Exception e) {
}
return sysOpenAccess;
}
public AuthenticationUser getUserByToken(String id,String requestAuthCode)
{
SysOpenAccess openAccess = getOpenAccess(id);
......@@ -140,7 +76,8 @@ public class UserDingtalkRegisterService {
request.setHttpMethod("GET");
OapiUserGetuserinfoResponse response = null;
try {
response = client.execute(request, openAccess.getAccessToken());
String accessToken =dingTalkTokenService.getAccessToken(openAccess.getAccessKey(),openAccess.getSecretKey());
response = client.execute(request, accessToken);
if(response.getErrcode()!=0||StringUtils.isEmpty(response.getUserid()))
throw new BadRequestAlertException("获取user失败","UserDingtalkRegisterService",response.getErrmsg());
} catch (ApiException e) {
......@@ -170,7 +107,6 @@ public class UserDingtalkRegisterService {
return null;
}
/**
* 钉钉服务端通过临时授权码code获取授权用户的个人信息
*
......@@ -222,77 +158,4 @@ public class UserDingtalkRegisterService {
return returnObj;
}
private static Map<String,TokenInfo> tokenMapping = new HashMap<>();
/**
* 适配当UAA接入多个钉钉应用的情况。
*
* @param appkey 钉钉appkey
* @return
*/
public boolean isExpire(String appkey) {
if (!tokenMapping.containsKey(appkey))
return true;
TokenInfo accessTokenInfo = tokenMapping.get(appkey);
if (accessTokenInfo == null)
return true;
String accessToken = accessTokenInfo.accessToken;
Long refreshtime = accessTokenInfo.lastRefreshTime;
if (StringUtils.isEmpty(accessToken) || refreshtime == null)
return true;
if (System.currentTimeMillis() < refreshtime + 7100000) {
System.currentTimeMillis();
return false;
}
return true;
}
private void setTokenInfo(String appkey, String token, Long refreshTime) {
if (StringUtils.isEmpty(token) || StringUtils.isEmpty(refreshTime))
return;
if (!tokenMapping.containsKey(appkey)) {
tokenMapping.put(appkey, new TokenInfo());
}
TokenInfo tokenInfo = tokenMapping.get(appkey);
tokenInfo.accessToken = token;
tokenInfo.lastRefreshTime = refreshTime;
}
private String getToken(String appkey){
if (!StringUtils.isEmpty(appkey)){
TokenInfo tokenInfo = tokenMapping.get(appkey);
if (tokenInfo != null)
return tokenMapping.get(appkey).accessToken;
}
return null;
}
/**
* 钉钉默认超时时间为2小时(7200秒),防止程序卡点,换成7100秒(100秒预留)
*/
private Long getLastRefreshTime(String appkey){
if (!StringUtils.isEmpty(appkey)){
TokenInfo tokenInfo = tokenMapping.get(appkey);
if (tokenInfo != null){
return tokenInfo.lastRefreshTime;
}
}
return System.currentTimeMillis()-7100001;
}
class TokenInfo{
String accessToken;
Long lastRefreshTime;
}
}
\ No newline at end of file
......@@ -141,7 +141,8 @@ public class apiSecurityConfig extends WebSecurityConfigurerAdapter {
.antMatchers("/uaa/getQQAppId").permitAll()
.antMatchers("/uaa/queryQQUserByCode").permitAll()
.antMatchers("/uaa/bindQQtoRegister").permitAll();
.antMatchers("/uaa/bindQQtoRegister").permitAll()
.antMatchers("/uaa/dingtalk/jsapi/sign").permitAll();
if (StringUtils.isNotBlank(excludesPattern)) {
for (String excludePattern : excludesPattern.split("\\s*,\\s*")) {
......
......@@ -157,4 +157,14 @@ public class UAACoreResource {
return ResponseEntity.status(HttpStatus.OK).body(jo);
}
/**
* 获取钉钉jsApi签名
* @param openAccessId
* @return
*/
@RequestMapping(method = RequestMethod.GET, value = "/uaa/dingtalk/jsapi/sign")
public ResponseEntity<JSONObject> getDingTalkJSSign(@Validated @NotBlank(message = "openAccessId不允许为空")@RequestParam ("openaccessid") String openAccessId,@NotBlank(message = "url不允许为空") @RequestParam ("url")String url){
return ResponseEntity.status(HttpStatus.OK).body(uaaCoreService.getDingTalkJSSign(openAccessId,url));
}
}
package cn.ibizlab.util.domain;
import lombok.*;
import java.io.Serializable;
@Builder
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class TokenInfo implements Serializable {
private static final long serialVersionUID = 1L;
private String accessToken;
private Long lastRefreshTime;
private String ticket;
}
......@@ -17,7 +17,7 @@ import java.io.InputStream;
* 权限:向uaa同步当前系统菜单、权限资源任务类
*/
@Slf4j
@Component
//@Component
//@ConditionalOnProperty( name = "ibiz.enablePermissionValid", havingValue = "true")
public class PermissionSyncJob implements ApplicationRunner {
......
Markdown 格式
0% or
您添加了 0 到此讨论。请谨慎行事。
先完成此消息的编辑!
想要评论请 注册