Bladeren bron

token过期自动刷新

guq 7 jaren geleden
bovenliggende
commit
a3490f0c09

+ 2 - 0
applications/sale/sale-server/src/main/resources/application.yml

@@ -37,6 +37,8 @@ spring:
   redis:
     host: 10.1.81.62
     port: 6379
+  profiles:
+    active: dev
 eureka:
   instance:
     leaseRenewalIntervalInSeconds: 10

+ 12 - 0
applications/sale/sale-server/src/main/resources/config/application-dev.yml

@@ -0,0 +1,12 @@
+eureka:
+  instance:
+    leaseRenewalIntervalInSeconds: 10
+    health-check-url-path: /actuator/health
+    status-page-url-path: /actuator/info
+    metadata-map:
+      user.name: ${spring.security.user.name}
+      user.password: ${spring.security.user.password}
+  client:
+    registryFetchIntervalSeconds: 5
+    serviceUrl:
+      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@127.0.0.1:8500/eureka/

+ 12 - 0
base-servers/auth/auth-api/src/main/java/com/usoftchina/saas/auth/api/AuthApi.java

@@ -1,12 +1,14 @@
 package com.usoftchina.saas.auth.api;
 
 import com.usoftchina.saas.auth.common.cookie.CookieInfo;
+import com.usoftchina.saas.auth.common.jwt.JwtInfo;
 import com.usoftchina.saas.auth.dto.AuthDTO;
 import com.usoftchina.saas.auth.dto.TokenDTO;
 import com.usoftchina.saas.base.Result;
 import org.springframework.cloud.openfeign.FeignClient;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestParam;
 
 /**
@@ -50,4 +52,14 @@ public interface AuthApi {
      */
     @PostMapping(value = "/sso/authorize")
     Result<AuthDTO> ssoAuthorize(CookieInfo info);
+
+    /**
+    * @Description 获取新token
+    * @Param: [info]
+    * @return: com.usoftchina.saas.base.Result<com.usoftchina.saas.auth.dto.TokenDTO>
+    * @Author: guq
+    * @Date: 2018/12/28
+    */
+    @PostMapping("/generateToken")
+    public Result<TokenDTO> generateToken(@RequestBody JwtInfo info);
 }

+ 7 - 1
base-servers/auth/auth-client/src/main/java/com/usoftchina/saas/auth/client/interceptor/AuthRestInterceptor.java

@@ -13,6 +13,7 @@ import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+import java.util.Enumeration;
 
 /**
  * @author yingp
@@ -37,7 +38,12 @@ public class AuthRestInterceptor extends HandlerInterceptorAdapter {
             if (annotation != null) {
                 return super.preHandle(request, response, handler);
             }
-            String token = request.getHeader(authConfig.getAuthHeader());
+            String token = null;
+            Enumeration<String> headers = request.getHeaders(authConfig.getAuthHeader());
+            while(headers.hasMoreElements()){
+                //取最后一个元素
+                token = headers.nextElement();
+            }
             if (null != token) {
                 JwtInfo infoFromToken = JwtHelper.getInfoFromToken(token, authConfig.getPublicKey());
                 BaseContextHolder.setAppId(infoFromToken.getAppId());

+ 3 - 0
base-servers/auth/auth-common/src/main/java/com/usoftchina/saas/auth/common/jwt/JwtInfo.java

@@ -21,6 +21,9 @@ public class JwtInfo implements Serializable{
         this.realName = realName;
     }
 
+    public JwtInfo() {
+    }
+
     public JwtInfo(String appId, Long companyId, Long userId, String userName, String realName) {
         this.appId = appId;
         this.companyId = companyId;

+ 37 - 2
base-servers/auth/auth-server/src/main/java/com/usoftchina/saas/auth/controller/AuthController.java

@@ -19,6 +19,7 @@ import com.usoftchina.saas.auth.po.VirtualAuthorizeLog;
 import com.usoftchina.saas.auth.service.AuthorizeCountService;
 import com.usoftchina.saas.auth.service.AuthorizeLogService;
 import com.usoftchina.saas.base.Result;
+import com.usoftchina.saas.cache.CacheKeyHelper;
 import com.usoftchina.saas.exception.BizException;
 import com.usoftchina.saas.exception.ExceptionCode;
 import com.usoftchina.saas.page.PageDefault;
@@ -98,7 +99,6 @@ public class AuthController {
         if (authorizeCountService.isFrozen(username)) {
             return Result.error(ExceptionCode.AUTH_FROZEN);
         }
-
         Result<AccountDTO> result = accountApi.validByUsernameAndPwd(username, password);
         if (result.isSuccess()) {
             authorizeCountService.clear(username);
@@ -114,6 +114,9 @@ public class AuthController {
             JwtInfo info = new JwtInfo(appId, companyId, accountDTO.getId(), accountDTO.getUsername(), accountDTO.getRealname());
             JwtToken jwtToken = JwtHelper.generateToken(info, privateKeyPath, expire);
             TokenDTO tokenDTO = BeanMapper.map(jwtToken, TokenDTO.class);
+            //登陆成功记入redis
+            String key = CacheKeyHelper.generatePublicKey(tokenDTO.getToken());
+            RedisUtil.set(key, tokenDTO, expire);
             // 登录日志
             authorizeLogService.save(AuthorizeLog.from(request)
                     .setAccountId(accountDTO.getId())
@@ -153,6 +156,9 @@ public class AuthController {
         JwtInfo info = new JwtInfo(appId, companyId, accountDTO.getId(), accountDTO.getUsername(), accountDTO.getRealname());
         JwtToken jwtToken = JwtHelper.generateToken(info, privateKeyPath, expire);
         TokenDTO tokenDTO = BeanMapper.map(jwtToken, TokenDTO.class);
+        //登陆成功记入redis
+        String key = CacheKeyHelper.generatePublicKey(tokenDTO.getToken());
+        RedisUtil.set(key, tokenDTO, expire);
         // 登录日志
         authorizeLogService.saveVirtual(VirtualAuthorizeLog.from(request)
                 .setMobile(Long.parseLong(accountDTO.getMobile()))
@@ -207,6 +213,9 @@ public class AuthController {
             if (null != companyDTO){
                 authDTO.setCompanyId(companyDTO.getId());
             }
+            //登陆成功记入redis
+            String key = CacheKeyHelper.generatePublicKey(tokenDTO.getToken());
+            RedisUtil.set(key, authDTO, expire);
             return Result.success(authDTO);
         }
         return Result.error(ExceptionCode.COOKIE_ILLEGAL_ARGUMENT);
@@ -262,8 +271,12 @@ public class AuthController {
                 JwtInfo jwtInfo = new JwtInfo(appId, companyId, accountDTO.getId(), accountDTO.getUsername(), accountDTO.getRealname());
                 JwtToken jwtToken = JwtHelper.generateToken(jwtInfo, privateKeyPath, expire);
                 TokenDTO tokenDTO = BeanMapper.map(jwtToken, TokenDTO.class);
+                AuthDTO authDTO = new AuthDTO(tokenDTO, accountDTO);
+                //登陆成功记入redis
+                String key = CacheKeyHelper.generatePublicKey(tokenDTO.getToken());
+                RedisUtil.set(key, authDTO, expire);
                 socketMessageApi.sendToClient(new ClientMessage(clientId, "/sso/callback",
-                        JsonUtils.toJsonString(new AuthDTO(tokenDTO, accountDTO))));
+                        JsonUtils.toJsonString(authDTO)));
             }
             ServletUtils.writeJsonPMessage(response, callback, true);
         }
@@ -310,6 +323,9 @@ public class AuthController {
             JwtInfo info = new JwtInfo(infoFromToken.getAppId(), companyId, infoFromToken.getUserId(),
                     infoFromToken.getUserName(), infoFromToken.getRealName());
             JwtToken jwtToken = JwtHelper.generateToken(info, privateKeyPath, expire);
+            //登陆成功记入redis
+            String key = CacheKeyHelper.generatePublicKey(jwtToken.getToken());
+            RedisUtil.set(key, info, expire);
             return Result.success(BeanMapper.map(jwtToken, TokenDTO.class));
         }
         return Result.error(ExceptionCode.COMPANY_NOT_BIND);
@@ -370,4 +386,23 @@ public class AuthController {
     public Result<PageInfo<AuthorizeLogDTO>> getLogs(@PageDefault PageRequest page) {
         return Result.success(authorizeLogService.findByPage(page));
     }
+    /**
+    * @Description 重新生成Token
+    * @Param: [info]
+    * @return: TokenDTO
+    * @Author: guq
+    * @Date: 2018/12/27
+    */
+    @PostMapping("/generateToken")
+    public Result<TokenDTO> generateToken(@RequestBody JwtInfo info) {
+        TokenDTO tokenDTO = null;
+        if (!StringUtils.isEmpty(info)) {
+            JwtToken jwtToken = JwtHelper.generateToken(info, privateKeyPath, expire);
+            tokenDTO = BeanMapper.map(jwtToken, TokenDTO.class);
+            //登陆成功记入redis
+            String key = CacheKeyHelper.generatePublicKey(jwtToken.getToken());
+            RedisUtil.set(key, info, expire);
+        }
+        return Result.success(tokenDTO);
+    }
 }

+ 9 - 0
base-servers/gateway-server/src/main/java/com/usoftchina/saas/gateway/config/AuthConfig.java

@@ -13,6 +13,15 @@ public class AuthConfig {
     private String publicKey;
     private String authHeader = "Authorization";
     private List<String> ignores;
+    private int expire;
+
+    public int getExpire() {
+        return expire;
+    }
+
+    public void setExpire(int expire) {
+        this.expire = expire;
+    }
 
     public String getPublicKey() {
         return publicKey;

+ 27 - 1
base-servers/gateway-server/src/main/java/com/usoftchina/saas/gateway/config/AuthFilter.java

@@ -12,12 +12,15 @@ import com.usoftchina.saas.auth.common.jwt.JwtInfo;
 import com.usoftchina.saas.auth.dto.AuthDTO;
 import com.usoftchina.saas.auth.dto.TokenDTO;
 import com.usoftchina.saas.base.Result;
+import com.usoftchina.saas.cache.CacheKeyHelper;
 import com.usoftchina.saas.context.BaseContextHolder;
 import com.usoftchina.saas.exception.BizException;
 import com.usoftchina.saas.exception.ExceptionCode;
 import com.usoftchina.saas.gateway.error.PermissionException;
 import com.usoftchina.saas.gateway.util.AntPathRequestMatcher;
 import com.usoftchina.saas.utils.CollectionUtils;
+import com.usoftchina.saas.utils.RedisUtil;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.context.properties.EnableConfigurationProperties;
 import org.springframework.cloud.gateway.filter.GatewayFilterChain;
@@ -60,7 +63,30 @@ public class AuthFilter implements GlobalFilter, Ordered {
             if (!isIgnore(exchange.getRequest())) {
                 // 鉴别身份信息
                 String token = getAuthToken(exchange.getRequest());
-                JwtInfo jwt = JwtHelper.getInfoFromToken(token, authConfig.getPublicKey());
+                String key = CacheKeyHelper.generatePublicKey(token);
+                //刷新时间
+                RedisUtil.expire(key, authConfig.getExpire());
+                JwtInfo jwt = null;
+                try {
+                    jwt = JwtHelper.getInfoFromToken(token, authConfig.getPublicKey());
+                } catch (BizException e) {
+                    if (ExceptionCode.JWT_TOKEN_EXPIRED.getCode() == e.getCode()) {
+                        jwt = (JwtInfo)RedisUtil.get(key);
+                        if (jwt == null) {
+                            throw new BizException(ExceptionCode.JWT_TOKEN_EXPIRED.getCode(), ExceptionCode.JWT_TOKEN_EXPIRED.getMessage());
+                        }
+                        Result<TokenDTO> result = authApi.generateToken(jwt);
+                        if (result.isSuccess() && null != result.getData()) {
+                            token = result.getData().getToken();
+                            //返回前端处理
+                            exchange.getResponse().getHeaders().add(authConfig.getAuthHeader(), token);
+                            //向headers中放token,记得build
+                            ServerHttpRequest request = exchange.getRequest().mutate().header(authConfig.getAuthHeader(), token).build();
+                            //将现在的request 变成 change对象
+                            exchange = exchange.mutate().request(request).build();
+                        }
+                    }
+                }
                 BaseContextHolder.setAppId(jwt.getAppId());
                 BaseContextHolder.setUserId(jwt.getUserId());
                 BaseContextHolder.setCompanyId(jwt.getCompanyId());

+ 1 - 0
base-servers/gateway-server/src/main/resources/application.yml

@@ -177,6 +177,7 @@ info:
 auth:
   auth-header: Authorization
   public-key: auth/pub.key
+  expire: 18000
   ignores:
     - /api/auth/authorize
     - /api/auth/virtual/authorize/**

+ 13 - 0
base-servers/ui-server/src/main/resources/config/application-dev.yml

@@ -0,0 +1,13 @@
+eureka:
+  instance:
+    leaseRenewalIntervalInSeconds: 10
+    health-check-url-path: /actuator/health
+    status-page-url-path: /actuator/info
+    prefer-ip-address: true
+    metadata-map:
+      user.name: ${spring.security.user.name}
+      user.password: ${spring.security.user.password}
+  client:
+    registryFetchIntervalSeconds: 5
+    serviceUrl:
+      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@127.0.0.1:8500/eureka/

+ 42 - 0
framework/core/src/main/java/com/usoftchina/saas/cache/RedisConfig.java

@@ -0,0 +1,42 @@
+package com.usoftchina.saas.cache;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+/**
+ * @author: guq
+ * @create: 2018-12-27 10:32
+ **/
+@Configuration
+public class RedisConfig {
+
+    @Bean
+    @SuppressWarnings("all")
+    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
+        RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
+        template.setConnectionFactory(factory);
+        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
+        ObjectMapper om = new ObjectMapper();
+        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
+        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
+        jackson2JsonRedisSerializer.setObjectMapper(om);
+        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
+        // key采用String的序列化方式
+        template.setKeySerializer(stringRedisSerializer);
+        // hash的key也采用String的序列化方式
+        template.setHashKeySerializer(stringRedisSerializer);
+        // value序列化方式采用jackson
+        template.setValueSerializer(jackson2JsonRedisSerializer);
+        // hash的value序列化方式采用jackson
+        template.setHashValueSerializer(jackson2JsonRedisSerializer);
+        template.afterPropertiesSet();
+        return template;
+    }
+}

+ 154 - 0
framework/core/src/main/java/com/usoftchina/saas/utils/RedisUtil.java

@@ -0,0 +1,154 @@
+package com.usoftchina.saas.utils;
+
+import com.usoftchina.saas.context.SpringContextHolder;
+import org.springframework.data.redis.core.RedisTemplate;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author: guq
+ * @create: 2018-12-27 10:39
+ **/
+public class RedisUtil {
+
+
+    private static RedisTemplate<String, Object> redisTemplate = SpringContextHolder.getBean("redisTemplate", RedisTemplate.class);
+
+    /**
+     * 指定缓存失效时间
+     * @param key 键
+     * @param time 时间(秒)
+     * @return
+     */
+    public static boolean expire(String key, long time) {
+        try {
+            if (time > 0) {
+                redisTemplate.expire(key, time, TimeUnit.SECONDS);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 根据key 获取过期时间
+     * @param key 键 不能为null
+     * @return 时间(秒) 返回0代表为永久有效
+     */
+    public static long getExpire(String key) {
+        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
+    }
+
+    /**
+    * @Description 判断key是否存在
+    * @Param: [key]
+    * @return: boolean
+    * @Author: guq
+    * @Date: 2018/12/27
+    */
+    public static boolean hasKey(String key) {
+        try {
+            return redisTemplate.hasKey(key);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+    * @Description 删除缓存
+    * @Param: [keys]
+    * @return: void
+    * @Author: guq
+    * @Date: 2018/12/27
+    */
+    @SuppressWarnings("unchecked")
+    public static void del(String... keys) {
+        if (null != keys && keys.length > 0) {
+            if (keys.length == 1) {
+                redisTemplate.delete(keys[0]);
+            } else {
+                redisTemplate.delete(CollectionUtils.arrayToList(keys));
+            }
+        }
+    }
+
+    /**
+    * @Description 获取key
+    * @Param: [key]
+    * @return: java.lang.Object
+    * @Author: guq
+    * @Date: 2018/12/27
+    */
+    public static Object get(String key) {
+        return key == null ? null : redisTemplate.opsForValue().get(key);
+    }
+
+    /**
+    * @Description 放入缓存
+    * @Param: [key, obj]
+    * @return: boolean
+    * @Author: guq
+    * @Date: 2018/12/27
+    */
+    public static boolean set(String key, Object obj) {
+        try {
+            redisTemplate.opsForValue().set(key, obj);
+            return true;
+        } catch (Exception e) {
+            return false;
+        }
+    }
+
+    /**
+    * @Description 添加时间
+    * @Param: [key, value, time]
+    * @return: boolean
+    * @Author: guq
+    * @Date: 2018/12/27
+    */
+    public static boolean set(String key, Object value, long time) {
+        try {
+            if (time > 0) {
+                redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
+            } else {
+                set(key, value);
+            }
+            return true;
+        }catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+    * @Description 要增加delta
+    * @Param: [key, delta]
+    * @return: long
+    * @Author: guq
+    * @Date: 2018/12/27
+    */
+    public long incr(String key, long delta) {
+        if (delta < 0) {
+            throw new RuntimeException("递增因子必须大于0");
+        }
+        return redisTemplate.opsForValue().increment(key, delta);
+    }
+
+
+    /**
+     * @Description 要减少delta
+     * @Param: [key, delta]
+     * @return: long
+     * @Author: guq
+     * @Date: 2018/12/27
+     */
+    public long decr(String key, long delta) {
+        if (delta < 0) {
+            throw new RuntimeException("递减因子必须大于0");
+        }
+        return redisTemplate.opsForValue().increment(key, -delta);
+    }
+}