|
@@ -0,0 +1,223 @@
|
|
|
+package com.diagbot.config;
|
|
|
+
|
|
|
+import com.diagbot.util.DateUtil;
|
|
|
+import com.diagbot.util.RedisUtils;
|
|
|
+import org.springframework.core.io.ClassPathResource;
|
|
|
+import org.springframework.core.io.Resource;
|
|
|
+import org.springframework.security.core.Authentication;
|
|
|
+import org.springframework.security.jwt.Jwt;
|
|
|
+import org.springframework.security.jwt.JwtHelper;
|
|
|
+import org.springframework.security.jwt.crypto.sign.RsaVerifier;
|
|
|
+import org.springframework.security.jwt.crypto.sign.SignatureVerifier;
|
|
|
+import org.springframework.security.oauth2.common.DefaultExpiringOAuth2RefreshToken;
|
|
|
+import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
|
|
|
+import org.springframework.security.oauth2.common.DefaultOAuth2RefreshToken;
|
|
|
+import org.springframework.security.oauth2.common.OAuth2AccessToken;
|
|
|
+import org.springframework.security.oauth2.common.OAuth2RefreshToken;
|
|
|
+import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
|
|
|
+import org.springframework.security.oauth2.common.util.JsonParser;
|
|
|
+import org.springframework.security.oauth2.common.util.JsonParserFactory;
|
|
|
+import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
|
|
+import org.springframework.security.oauth2.provider.approval.Approval;
|
|
|
+import org.springframework.security.oauth2.provider.approval.ApprovalStore;
|
|
|
+import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
|
|
|
+import org.springframework.security.oauth2.provider.token.store.JwtClaimsSetVerifier;
|
|
|
+import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
|
|
|
+import org.springframework.security.oauth2.provider.approval.Approval.ApprovalStatus;
|
|
|
+import org.springframework.util.FileCopyUtils;
|
|
|
+
|
|
|
+import java.io.IOException;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.Collection;
|
|
|
+import java.util.Collections;
|
|
|
+import java.util.Date;
|
|
|
+import java.util.HashSet;
|
|
|
+import java.util.Iterator;
|
|
|
+import java.util.Map;
|
|
|
+
|
|
|
+/**
|
|
|
+ * @Description:token续签
|
|
|
+ * @Author songxl
|
|
|
+ * @Date 2021/12/17
|
|
|
+ */
|
|
|
+public class MyJwtTokenStore extends JwtTokenStore {
|
|
|
+ private JwtAccessTokenConverter jwtTokenEnhancer;
|
|
|
+ private ApprovalStore approvalStore;
|
|
|
+ private JsonParser objectMapper = JsonParserFactory.create();
|
|
|
+ private JwtClaimsSetVerifier jwtClaimsSetVerifier = new NoOpJwtClaimsSetVerifier();
|
|
|
+ private SignatureVerifier verifier;
|
|
|
+ private RedisUtils redisUtils;
|
|
|
+ public MyJwtTokenStore(JwtAccessTokenConverter jwtTokenEnhancer,RedisUtils redisUtils) {
|
|
|
+ super(jwtTokenEnhancer);
|
|
|
+ verifier = createVerifier();
|
|
|
+ this.jwtTokenEnhancer = jwtTokenEnhancer;
|
|
|
+ this.redisUtils = redisUtils;
|
|
|
+ }
|
|
|
+
|
|
|
+ private SignatureVerifier createVerifier() {
|
|
|
+ Resource resource = new ClassPathResource("public.cert");
|
|
|
+ String publicKey;
|
|
|
+ try {
|
|
|
+ publicKey = new String(FileCopyUtils.copyToByteArray(resource.getInputStream()));
|
|
|
+ } catch (IOException e) {
|
|
|
+ throw new RuntimeException(e);
|
|
|
+ }
|
|
|
+ return new RsaVerifier(publicKey);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setApprovalStore(ApprovalStore approvalStore) {
|
|
|
+ this.approvalStore = approvalStore;
|
|
|
+ }
|
|
|
+
|
|
|
+ public OAuth2Authentication readAuthentication(OAuth2AccessToken token) {
|
|
|
+ return this.readAuthentication(token.getValue());
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ public void storeAccessToken(OAuth2AccessToken token, OAuth2Authentication authentication) {
|
|
|
+ }
|
|
|
+
|
|
|
+ public OAuth2AccessToken readAccessToken(String tokenValue) {
|
|
|
+ DefaultOAuth2AccessToken accessToken = (DefaultOAuth2AccessToken) this.convertAccessToken(tokenValue);
|
|
|
+ OAuth2AccessToken newAccessToken = updateTokenOutTime(accessToken);
|
|
|
+ if (this.jwtTokenEnhancer.isRefreshToken(accessToken)) {
|
|
|
+ throw new InvalidTokenException("Encoded token is a refresh token");
|
|
|
+ } else {
|
|
|
+ return newAccessToken;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private OAuth2AccessToken updateTokenOutTime(DefaultOAuth2AccessToken accessToken) {
|
|
|
+ if(accessToken.getAdditionalInformation()!=null&&accessToken.getAdditionalInformation().containsKey("user_id")){
|
|
|
+ //通过用户id获取redis存储的token过期时间
|
|
|
+ Object userIdObj = accessToken.getAdditionalInformation().get("user_id");
|
|
|
+ Integer value =(Integer) redisUtils.get("user:refreshToken:outTime_" + userIdObj);
|
|
|
+ if (value!=null){
|
|
|
+ //更新token过期时间为明天
|
|
|
+ accessToken.setExpiration(DateUtil.addDay(new Date(),1));
|
|
|
+ //将这个时间重新存到redis
|
|
|
+ redisUtils.set("user:refreshToken:outTime_" + userIdObj, value, value);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return accessToken;
|
|
|
+ }
|
|
|
+
|
|
|
+ private OAuth2AccessToken convertAccessToken(String tokenValue) {
|
|
|
+ return this.jwtTokenEnhancer.extractAccessToken(tokenValue, decode(tokenValue));
|
|
|
+ }
|
|
|
+
|
|
|
+ public void removeAccessToken(OAuth2AccessToken token) {
|
|
|
+ }
|
|
|
+
|
|
|
+ public void storeRefreshToken(OAuth2RefreshToken refreshToken, OAuth2Authentication authentication) {
|
|
|
+ }
|
|
|
+
|
|
|
+ public OAuth2RefreshToken readRefreshToken(String tokenValue) {
|
|
|
+ OAuth2AccessToken encodedRefreshToken = this.convertAccessToken(tokenValue);
|
|
|
+ OAuth2RefreshToken refreshToken = this.createRefreshToken(encodedRefreshToken);
|
|
|
+ if (this.approvalStore != null) {
|
|
|
+ OAuth2Authentication authentication = this.readAuthentication(tokenValue);
|
|
|
+ if (authentication.getUserAuthentication() != null) {
|
|
|
+ String userId = authentication.getUserAuthentication().getName();
|
|
|
+ String clientId = authentication.getOAuth2Request().getClientId();
|
|
|
+ Collection<Approval> approvals = this.approvalStore.getApprovals(userId, clientId);
|
|
|
+ Collection<String> approvedScopes = new HashSet();
|
|
|
+ Iterator var9 = approvals.iterator();
|
|
|
+
|
|
|
+ while(var9.hasNext()) {
|
|
|
+ Approval approval = (Approval)var9.next();
|
|
|
+ if (approval.isApproved()) {
|
|
|
+ approvedScopes.add(approval.getScope());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!approvedScopes.containsAll(authentication.getOAuth2Request().getScope())) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return refreshToken;
|
|
|
+ }
|
|
|
+
|
|
|
+ private OAuth2RefreshToken createRefreshToken(OAuth2AccessToken encodedRefreshToken) {
|
|
|
+ if (!this.jwtTokenEnhancer.isRefreshToken(encodedRefreshToken)) {
|
|
|
+ throw new InvalidTokenException("Encoded token is not a refresh token");
|
|
|
+ } else {
|
|
|
+ return (OAuth2RefreshToken)(encodedRefreshToken.getExpiration() != null ? new DefaultExpiringOAuth2RefreshToken(encodedRefreshToken.getValue(), encodedRefreshToken.getExpiration()) : new DefaultOAuth2RefreshToken(encodedRefreshToken.getValue()));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public OAuth2Authentication readAuthenticationForRefreshToken(OAuth2RefreshToken token) {
|
|
|
+ return this.readAuthentication(token.getValue());
|
|
|
+ }
|
|
|
+
|
|
|
+ public void removeRefreshToken(OAuth2RefreshToken token) {
|
|
|
+ this.remove(token.getValue());
|
|
|
+ }
|
|
|
+
|
|
|
+ public void removeAccessTokenUsingRefreshToken(OAuth2RefreshToken refreshToken) {
|
|
|
+ }
|
|
|
+
|
|
|
+ public OAuth2AccessToken getAccessToken(OAuth2Authentication authentication) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ public Collection<OAuth2AccessToken> findTokensByClientIdAndUserName(String clientId, String userName) {
|
|
|
+ return Collections.emptySet();
|
|
|
+ }
|
|
|
+
|
|
|
+ public Collection<OAuth2AccessToken> findTokensByClientId(String clientId) {
|
|
|
+ return Collections.emptySet();
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setTokenEnhancer(JwtAccessTokenConverter tokenEnhancer) {
|
|
|
+ this.jwtTokenEnhancer = tokenEnhancer;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void remove(String token) {
|
|
|
+ if (this.approvalStore != null) {
|
|
|
+ OAuth2Authentication auth = this.readAuthentication(token);
|
|
|
+ String clientId = auth.getOAuth2Request().getClientId();
|
|
|
+ Authentication user = auth.getUserAuthentication();
|
|
|
+ if (user != null) {
|
|
|
+ Collection<Approval> approvals = new ArrayList();
|
|
|
+ Iterator var6 = auth.getOAuth2Request().getScope().iterator();
|
|
|
+
|
|
|
+ while(var6.hasNext()) {
|
|
|
+ String scope = (String)var6.next();
|
|
|
+ approvals.add(new Approval(user.getName(), clientId, scope, new Date(), ApprovalStatus.APPROVED));
|
|
|
+ }
|
|
|
+
|
|
|
+ this.approvalStore.revokeApprovals(approvals);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ protected Map<String, Object> decode(String token) {
|
|
|
+ try {
|
|
|
+ Jwt jwt = JwtHelper.decodeAndVerify(token,verifier);
|
|
|
+ String claimsStr = jwt.getClaims();
|
|
|
+ Map<String, Object> claims = this.objectMapper.parseMap(claimsStr);
|
|
|
+ if (claims.containsKey("exp") && claims.get("exp") instanceof Integer) {
|
|
|
+ Integer intValue = (Integer)claims.get("exp");
|
|
|
+ claims.put("exp", new Long((long)intValue));
|
|
|
+ }
|
|
|
+
|
|
|
+ jwtClaimsSetVerifier.verify(claims);
|
|
|
+ return claims;
|
|
|
+ } catch (Exception var6) {
|
|
|
+ throw new InvalidTokenException("Cannot convert access token to JSON", var6);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private class NoOpJwtClaimsSetVerifier implements JwtClaimsSetVerifier {
|
|
|
+ private NoOpJwtClaimsSetVerifier() {
|
|
|
+ }
|
|
|
+
|
|
|
+ public void verify(Map<String, Object> claims) throws InvalidTokenException {
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|