diff --git a/docus-client-interface/src/main/java/com/docus/server/api/recovery/RcvSysUserApi.java b/docus-client-interface/src/main/java/com/docus/server/api/recovery/RcvSysUserApi.java index 8b71862..b266850 100644 --- a/docus-client-interface/src/main/java/com/docus/server/api/recovery/RcvSysUserApi.java +++ b/docus-client-interface/src/main/java/com/docus/server/api/recovery/RcvSysUserApi.java @@ -6,6 +6,7 @@ import com.docus.server.dto.recovery.rcvsysuser.AddRcvSysUserDTO; import com.docus.server.dto.recovery.rcvsysuser.DeleteRcvSysUserDTO; import com.docus.server.dto.recovery.rcvsysuser.EditRcvSysUserDTO; import com.docus.server.dto.recovery.rcvsysuser.LoginRcvSysUserDTO; +import com.docus.server.vo.recovery.UserInfoView; import com.docus.server.vo.recovery.rcvsysuser.RcvSysUserVO; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.DeleteMapping; @@ -33,15 +34,16 @@ import java.util.List; public interface RcvSysUserApi { /** * 登录 + * @return */ @PostMapping("/login") - void login(@RequestBody LoginRcvSysUserDTO loginRcvSysUserDTO); + UserInfoView login(@RequestBody LoginRcvSysUserDTO loginRcvSysUserDTO); /** * 退出登录 */ @GetMapping("/logout") - void logout(); + void logout(@RequestParam("token") String token); /** * 按主键查询 diff --git a/docus-client-interface/src/main/java/com/docus/server/dto/recovery/rcvsysuser/AddRcvSysUserDTO.java b/docus-client-interface/src/main/java/com/docus/server/dto/recovery/rcvsysuser/AddRcvSysUserDTO.java index 133e48e..4f74044 100644 --- a/docus-client-interface/src/main/java/com/docus/server/dto/recovery/rcvsysuser/AddRcvSysUserDTO.java +++ b/docus-client-interface/src/main/java/com/docus/server/dto/recovery/rcvsysuser/AddRcvSysUserDTO.java @@ -1,5 +1,6 @@ package com.docus.server.dto.recovery.rcvsysuser; +import com.docus.server.enums.EffectiveEnum; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.AllArgsConstructor; @@ -51,7 +52,7 @@ public class AddRcvSysUserDTO implements Serializable { private String userPosition; @ApiModelProperty(value = "是否有效,0:无效,1:有效") - private Integer effective; + private EffectiveEnum effective; @ApiModelProperty(value = "入库时间") private Date createTime; diff --git a/docus-client-interface/src/main/java/com/docus/server/dto/recovery/rcvsysuser/EditRcvSysUserDTO.java b/docus-client-interface/src/main/java/com/docus/server/dto/recovery/rcvsysuser/EditRcvSysUserDTO.java index 4c4c938..2d9d4e0 100644 --- a/docus-client-interface/src/main/java/com/docus/server/dto/recovery/rcvsysuser/EditRcvSysUserDTO.java +++ b/docus-client-interface/src/main/java/com/docus/server/dto/recovery/rcvsysuser/EditRcvSysUserDTO.java @@ -1,5 +1,6 @@ package com.docus.server.dto.recovery.rcvsysuser; +import com.docus.server.enums.EffectiveEnum; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.AllArgsConstructor; @@ -52,7 +53,7 @@ public class EditRcvSysUserDTO implements Serializable { private String userPosition; @ApiModelProperty(value = "是否有效,0:无效,1:有效") - private Integer effective; + private EffectiveEnum effective; @ApiModelProperty(value = "入库时间") private Date createTime; diff --git a/docus-client-interface/src/main/java/com/docus/server/vo/recovery/UserInfoView.java b/docus-client-interface/src/main/java/com/docus/server/vo/recovery/UserInfoView.java new file mode 100644 index 0000000..0df5033 --- /dev/null +++ b/docus-client-interface/src/main/java/com/docus/server/vo/recovery/UserInfoView.java @@ -0,0 +1,55 @@ +package com.docus.server.vo.recovery; + +import lombok.Data; +import org.springframework.data.annotation.Transient; + +import java.util.Map; +import java.util.Set; + +@Data +public class UserInfoView { + + private String token; + private String userId; + //用户账号 + private String userName; + ///用户姓名 + private String realName; + //角色Id + private String roleId; + //角色名称 + private String roleName; + //有 权限的菜单和功能按钮 + private Set menus; + ///用户数据权限标识 + private String privilegeMd5; + + //数据权限ID + private Set privilegeIds; + private Set privilegeOwnerIds; + //用户默认访问的城市 + private Integer defau1tAdminCode; + ///用户默认访问的企业 + private String defaultownerId; + //当前城市下有权限的企业ID->企业名称,不持久化到redis + @Transient + private Map currentAdminOwners; + //当前城市下有权限的企业,不持久化到redis +// @Transient +// private List currentAdminOwnerInfos; + // 所有有权限的城市区划和城市名称 + private Map privilegeAdmins; + //当前应用ID + private String appId; + ///用户密码用于cti连接 + @Transient + private String password; + //是否超管 + private boolean isSuperAdmin = false; + + private String hostSystem; + //.中心点纬度 + private String centerLatitude; + private String centerLongitude; + +} diff --git a/docus-recovery/src/main/java/com/docus/server/RecoveryBootstrap.java b/docus-recovery/src/main/java/com/docus/server/RecoveryBootstrap.java index 429b7db..5660017 100644 --- a/docus-recovery/src/main/java/com/docus/server/RecoveryBootstrap.java +++ b/docus-recovery/src/main/java/com/docus/server/RecoveryBootstrap.java @@ -15,4 +15,5 @@ public class RecoveryBootstrap { System.setProperty("javax.xml.parsers.DocumentBuilderFactory", "com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl"); SpringApplication.run(RecoveryBootstrap.class, args); } + } diff --git a/docus-recovery/src/main/java/com/docus/server/common/ApiRequestContext.java b/docus-recovery/src/main/java/com/docus/server/common/ApiRequestContext.java new file mode 100644 index 0000000..1d046f8 --- /dev/null +++ b/docus-recovery/src/main/java/com/docus/server/common/ApiRequestContext.java @@ -0,0 +1,194 @@ +package com.docus.server.common; + +import com.docus.server.constants.BusinessConstant; +import com.docus.server.vo.recovery.UserInfoView; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.Objects; + +public class ApiRequestContext { + //线程变量,请求线程内有效 + private static final ThreadLocal current = new ThreadLocal<>(); + //#xreales t + private HttpServletRequest request; + //i#Rresponse + private HttpServletResponse response; + //请求的方法 + private String action; + private Integer adminCode; + //当前访问的子系统 + private String systemCode; + //子系统分组,( PC端和移动端设置同一 分组,以便短信、通知等信息能过滤出来) + private String appGroup; + private String ownerId; + //当前访问的应用ID (公众出行子系统有效) + private String appId; + //当前登录的用户信息 + private UserInfoView userInfoView; + private boolean isInternal = true; + //是否授杖内部微服务接口(跳过token验证)访问 + private boolean grantInternalRequest = false; + + private ApiRequestContext() { + + } + + //初始化 + public static void init(HttpServletRequest request, HttpServletResponse response, UserInfoView userInfoview, String action) { + current.remove(); + ApiRequestContext context = new ApiRequestContext(); + context.request = request; + context.response = response; + context.userInfoView = userInfoview; + context.action = action; + String ownerId = request.getHeader(BusinessConstant.HEADER_OWNER_ID); + String systemCode = request.getHeader(BusinessConstant.HEADER_SYSTEM_CODE); + String appId = request.getHeader(BusinessConstant.HEADER_APP_ID); + String networkType = request.getHeader(BusinessConstant.HEADER_NETWORK_TYPE); //0:FIP, 1:H01 + context.systemCode = systemCode; + context.ownerId = ownerId; + context.appId = appId; + context.isInternal = Objects.equals(networkType, "0"); + current.set(context); + } + + //初始化 + public static void init(HttpServletRequest request, HttpServletResponse response, UserInfoView userInfoview, String action, String appGroup) { + current.remove(); + ApiRequestContext context = new ApiRequestContext(); + context.request = request; + context.response = response; + context.userInfoView = userInfoview; + context.action = action; + String ownerId = request.getHeader(BusinessConstant.HEADER_OWNER_ID); + String systemCode = request.getHeader(BusinessConstant.HEADER_SYSTEM_CODE); + String appId = request.getHeader(BusinessConstant.HEADER_APP_ID); + String networkType = request.getHeader(BusinessConstant.HEADER_NETWORK_TYPE); //0:FIP, 1:H01 + context.systemCode = systemCode; + context.ownerId = ownerId; + context.appId = appId; + context.appGroup = appGroup; + context.isInternal = Objects.equals(networkType, "0"); + current.set(context); + } + + //获取当前现场request + public static ApiRequestContext get() { + return current.get(); + } + + //清除线程变量 + public static void clear() { + current.remove(); + } + + public HttpServletRequest getRequest() { + return request; + } + + public void setRequest(HttpServletRequest request) { + this.request = request; + } + + public HttpServletResponse getResponse() { + return response; + } + + public void setResponse(HttpServletResponse response) { + this.response = response; + } + + public String getAction() { + return action; + } + + public void setAction(String action) { + this.action = action; + } + + public Integer getAdminCode() { + return adminCode; + } + + public void setAdminCode(Integer adminCode) { + this.adminCode = adminCode; + } + + public String getSystemCode() { + return systemCode; + } + + public void setSystemCode(String systemCode) { + this.systemCode = systemCode; + } + + public String getAppGroup() { + return appGroup; + } + + public void setAppGroup(String appGroup) { + this.appGroup = appGroup; + } + + public String getOwnerId() { + return ownerId; + } + + public void setOwnerId(String ownerId) { + this.ownerId = ownerId; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public UserInfoView getUserInfoView() { + return userInfoView; + } + + public void setUserInfoView(UserInfoView userInfoView) { + this.userInfoView = userInfoView; + } + + public boolean isInternal() { + return isInternal; + } + + public void setInternal(boolean internal) { + isInternal = internal; + } + + public boolean getIsGrantInternalRequest() { + if (this.grantInternalRequest) { + this.grantInternalRequest = false; + return true; + } + return false; + } + + public void setGrantInternalRequest(boolean grantInternalRequest) { + this.grantInternalRequest = grantInternalRequest; + } + + //授权本线程访问内部微服务接口一次,跳过token一次 + public static void grantInternalRequestOnce() { + if (current.get() == null) { + ApiRequestContext apiRequestContext = new ApiRequestContext(); + current.set(apiRequestContext); + } + current.get().grantInternalRequest = true; + } + + public String getUserId() { + return userInfoView != null ? userInfoView.getUserId() : null; + } + + public String getToken() { + return userInfoView != null ? userInfoView.getToken() : null; + } +} diff --git a/docus-recovery/src/main/java/com/docus/server/common/CloudBaseConfig.java b/docus-recovery/src/main/java/com/docus/server/common/CloudBaseConfig.java new file mode 100644 index 0000000..68141f2 --- /dev/null +++ b/docus-recovery/src/main/java/com/docus/server/common/CloudBaseConfig.java @@ -0,0 +1,48 @@ +package com.docus.server.common; + +import com.docus.server.constants.BusinessConstant; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import java.util.Arrays; +import java.util.List; + +@Configuration +public class CloudBaseConfig implements WebMvcConfigurer { + //请求参数拦截器 + @Bean("recoveryRequestContextInterceptor") + public RequestContextInterceptor requestContextInterceptor() { + return new RequestContextInterceptor(); + } + + //Feign请求拦截器 + @ConditionalOnMissingBean + @Bean() + public FeignRequestInterceptor feignRequestInterceptor() { + return new FeignRequestInterceptor(); + } + + //token验证拦截器,不需要token验证的方法加@IgnoreVa7idate + @Bean + public TokenInterceptor tokenTntercentor() { + return new TokenInterceptor(BusinessConstant.HEADER_API_TOKEN, BusinessConstant.HEADER_USER_ID, BusinessConstant.REDIS_KEY_USER_TOKEN_PREFIX); + } + + @Override + public void addInterceptors(InterceptorRegistry registry) { + List staticResource = Arrays.asList("/swagger-ui/**", "/webjars/**", "/v3/**", "/swagger-resources/**"); + registry.addInterceptor(tokenTntercentor()).excludePathPatterns(staticResource); + registry.addInterceptor(requestContextInterceptor()).excludePathPatterns(staticResource); + } + + + @ConditionalOnMissingBean + @Bean + public RedisStringService redisStringService() { + return new RedisStringService(); + } + +} diff --git a/docus-recovery/src/main/java/com/docus/server/common/FeignRequestInterceptor.java b/docus-recovery/src/main/java/com/docus/server/common/FeignRequestInterceptor.java new file mode 100644 index 0000000..7f3dcb0 --- /dev/null +++ b/docus-recovery/src/main/java/com/docus/server/common/FeignRequestInterceptor.java @@ -0,0 +1,57 @@ +package com.docus.server.common; + +import com.docus.infrastructure.core.db.KeyGenerator; +import com.docus.server.constants.BusinessConstant; +import com.docus.server.vo.recovery.UserInfoView; +import feign.RequestInterceptor; +import feign.RequestTemplate; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.concurrent.TimeUnit; + +//feign微服务之间调用header传入用户登录信息 +public class FeignRequestInterceptor implements RequestInterceptor { + private static final String internalUserName = " internal"; + private String token; + @Autowired + private RedisStringService redisStringService; + + @Override + public void apply(RequestTemplate requestTemplate) { + ApiRequestContext requestContext = ApiRequestContext.get(); + if (requestContext != null) { + if (requestContext.getIsGrantInternalRequest()) { + if (token == null || redisStringService.getValue(BusinessConstant.REDIS_KEY_USER_TOKEN_PREFIX + token, UserInfoView.class) != null) { + initToken(); + } + requestTemplate.header(BusinessConstant.HEADER_SYSTEM_CODE, internalUserName); + requestTemplate.header(BusinessConstant.HEADER_USER_ID, internalUserName); + requestTemplate.header(BusinessConstant.HEADER_API_TOKEN, token); + } else { + requestTemplate.header(BusinessConstant.HEADER_SYSTEM_CODE, requestContext.getSystemCode()); + requestTemplate.header(BusinessConstant.HEADER_USER_ID, requestContext.getUserId()); + requestTemplate.header(BusinessConstant.HEADER_API_TOKEN, requestContext.getToken()); + if (requestContext.getAdminCode() != null) { + requestTemplate.header(BusinessConstant.HEADER_ADMIN_CODE, requestContext.getAdminCode().toString()); + } + if (requestContext.getOwnerId() != null) { + requestTemplate.header(BusinessConstant.HEADER_OWNER_ID, requestContext.getOwnerId()); + } + if (requestContext.getAppId() != null) { + requestTemplate.header(BusinessConstant.HEADER_APP_ID, requestContext.getAppId()); + } + } + } + } + + //创建虚拟用户和token,用于微服务直接调用 + private void initToken() { + token = KeyGenerator.genId(); + UserInfoView userInfoview = new UserInfoView(); + userInfoview.setToken(token); + userInfoview.setUserId(internalUserName); + userInfoview.setUserName(internalUserName); + userInfoview.setRealName(internalUserName); + redisStringService.setValue(BusinessConstant.REDIS_KEY_USER_TOKEN_PREFIX + token, userInfoview, 3, TimeUnit.MINUTES); + } +} diff --git a/docus-recovery/src/main/java/com/docus/server/common/IgnoreValidate.java b/docus-recovery/src/main/java/com/docus/server/common/IgnoreValidate.java new file mode 100644 index 0000000..aef0f76 --- /dev/null +++ b/docus-recovery/src/main/java/com/docus/server/common/IgnoreValidate.java @@ -0,0 +1,12 @@ +package com.docus.server.common; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +//忽略鉴权验证 +@Target({ ElementType.METHOD,ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface IgnoreValidate { +} diff --git a/docus-recovery/src/main/java/com/docus/server/common/RedisStringService.java b/docus-recovery/src/main/java/com/docus/server/common/RedisStringService.java new file mode 100644 index 0000000..47a327c --- /dev/null +++ b/docus-recovery/src/main/java/com/docus/server/common/RedisStringService.java @@ -0,0 +1,47 @@ +package com.docus.server.common; + +import com.docus.infrastructure.util.JsonUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.StringRedisTemplate; + +import java.util.concurrent.TimeUnit; + +//redis string类型操作类 +public class RedisStringService { + + @Autowired + private StringRedisTemplate stringRedisTemplate; + + + //文设置值,保存为String类型 + public void setValue(String key, Object value) { + stringRedisTemplate.opsForValue().set(key, JsonUtils.toJson(value)); + } + + //设置值,保存为String类型 + + public void setValue(String key, Object value, long timeout, TimeUnit unit) { + stringRedisTemplate.opsForValue().set(key, JsonUtils.toJson(value), timeout, unit); + } +//获取String类型值,并自动反序列化为对象 + + public T getValue(String key, Class type) { + String value = stringRedisTemplate.opsForValue().get(key); + return JsonUtils.fromJson(value, type); + } +//重新设置过期时间 + + public void setExpire(String key, long timeout, TimeUnit unit) { + stringRedisTemplate.expire(key, timeout, unit); + } + + //删除 + public void delete(String key) { + stringRedisTemplate.delete(key); + } +//key是否存在 + + public Boolean hasKey(String key) { + return stringRedisTemplate.hasKey(key); + } +} diff --git a/docus-recovery/src/main/java/com/docus/server/common/RequestContextInterceptor.java b/docus-recovery/src/main/java/com/docus/server/common/RequestContextInterceptor.java new file mode 100644 index 0000000..7ecfce0 --- /dev/null +++ b/docus-recovery/src/main/java/com/docus/server/common/RequestContextInterceptor.java @@ -0,0 +1,58 @@ +package com.docus.server.common; + +import com.docus.server.constants.BusinessConstant; +import com.docus.server.vo.recovery.UserInfoView; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerInterceptor; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.concurrent.ConcurrentHashMap; + +public class RequestContextInterceptor implements HandlerInterceptor { + @Autowired + private RedisStringService redisStringService; + @Autowired(required = false) +// private RtmAppApi rtmAppApi; + private volatile static ConcurrentHashMap appInfoMap = new ConcurrentHashMap<>(); + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + String token = request.getHeader(BusinessConstant.HEADER_API_TOKEN); + UserInfoView userInfoview = redisStringService.getValue(BusinessConstant.REDIS_KEY_USER_TOKEN_PREFIX + token, UserInfoView.class); + String systemCode = request.getHeader(BusinessConstant.HEADER_SYSTEM_CODE); + String appGroup = null; + if (StringUtils.isNotBlank(systemCode)) { + if (appInfoMap.containsKey(systemCode)) { + appGroup = appInfoMap.get(systemCode); + } else { +// if (rtmAppApi != null) { +// RtmApp rtmApp = rtmAppApi.getAppInfoByAppEname(systemCode); +// appGroup = rtmApp == null ? null : rtmApp.getAppGroup(); +// if (StringUtils.isNotBlank(appGroup)) { +// appInfoMap.put(systemCode, appGroup); +// } +// } + } + } + ApiRequestContext.init(request, response, userInfoview, getAction(handler), appGroup); + return true; + } + + @Override + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { + //清除线程变量 + ApiRequestContext.clear(); + } + + private String getAction(Object handler) { + if (handler instanceof HandlerMethod) { + HandlerMethod handlerMethod = (HandlerMethod) handler; + String className = handlerMethod.getBeanType().getSimpleName(); + return className + handlerMethod.getMethod().getName(); + } + return null; + } +} diff --git a/docus-recovery/src/main/java/com/docus/server/common/TokenInterceptor.java b/docus-recovery/src/main/java/com/docus/server/common/TokenInterceptor.java new file mode 100644 index 0000000..f5274c4 --- /dev/null +++ b/docus-recovery/src/main/java/com/docus/server/common/TokenInterceptor.java @@ -0,0 +1,105 @@ +package com.docus.server.common; + +import com.alibaba.fastjson.JSON; +import com.docus.infrastructure.web.exception.ApiException; +import com.docus.infrastructure.web.exception.ExceptionCode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.util.StringUtils; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.concurrent.TimeUnit; + +public class TokenInterceptor extends HandlerInterceptorAdapter { + + private static final Logger logger = LoggerFactory.getLogger(TokenInterceptor.class); + + @Autowired + private StringRedisTemplate stringRedisTemplate; + + //A/访问后自动延长重置token过期时间 + private boolean overtimeAfterAccess = true; + + public void setovertimeAfterAccess(boolean overtimeAfterAccess) { + this.overtimeAfterAccess = overtimeAfterAccess; + } + + private String tokenHeaderName = "api-token"; + private String userIdHeaderName = "user-id"; + private String tokenRedisKeyPrefix = "apiToken:"; + private String userIdPropertyName = "userId"; + + public TokenInterceptor() { + + } + + public TokenInterceptor(String tokenHeaderName, String userIdHeaderName, String tokenRedisKeyPrefix) { + this.tokenHeaderName = tokenHeaderName; + this.userIdHeaderName = userIdHeaderName; + tokenRedisKeyPrefix = tokenRedisKeyPrefix; + } + + public TokenInterceptor(String tokenHeaderName, String userIdHeaderName, String tokenRedisKeyPrefix, String userIdPropertyName) { + this.tokenHeaderName = tokenHeaderName; + this.userIdHeaderName = userIdHeaderName; + tokenRedisKeyPrefix = tokenRedisKeyPrefix; + this.userIdPropertyName = userIdPropertyName; + } + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + if (handler instanceof HandlerMethod) { + HandlerMethod handlerMethod = (HandlerMethod) handler; + Class controller = handlerMethod.getMethod().getDeclaringClass(); + if (handlerMethod.hasMethodAnnotation(IgnoreValidate.class) || controller.getAnnotation(IgnoreValidate.class) != null) { + //忽略验证 + return super.preHandle(request, response, handler); + } + } + validateToken(request); + return super.preHandle(request, response, handler); + } + + //验证token是否有效,并把token对应的用户信息存入上下文变量 + protected void validateToken(HttpServletRequest request) { + String token = request.getHeader(tokenHeaderName); + if (StringUtils.isEmpty(token)) { + logger.info("token is empty"); + throw new ApiException(ExceptionCode.TokenError); + } + + String redisKey = tokenRedisKeyPrefix + token; + if (stringRedisTemplate == null) { + throw new RuntimeException("启用token验证依赖redis"); + } + String redisValue = stringRedisTemplate.opsForValue().get(redisKey); + if (StringUtils.isEmpty(redisValue)) { + logger.info("token {} is not exist or expired", token); + throw new ApiException(ExceptionCode.TokenError); + } + String userId = JSON.parseObject(redisValue).getString(userIdPropertyName); + if (StringUtils.isEmpty(userId)) { + logger.info("userId property {} not exists", userIdPropertyName); + throw new ApiException(ExceptionCode.TokenError); + } + String headerUserId = request.getHeader(userIdHeaderName); + if (!userId.equalsIgnoreCase(headerUserId)) { + //非法 token , token和userid不匹配 + logger.info("token {} is not. match userId {}", token, headerUserId); + throw new ApiException(ExceptionCode.TokenError); + } + //重置token过期时间 + if (overtimeAfterAccess) { + Long expireMinutes = stringRedisTemplate.getExpire(redisKey, TimeUnit.MINUTES); + //-1表示不过期 + if (expireMinutes > -1 && expireMinutes < 60) { + stringRedisTemplate.expire(redisKey, 60, TimeUnit.MINUTES); + } + } + } +} diff --git a/docus-recovery/src/main/java/com/docus/server/controller/RcvSysUserController.java b/docus-recovery/src/main/java/com/docus/server/controller/RcvSysUserController.java index 6c2b13f..bcce042 100644 --- a/docus-recovery/src/main/java/com/docus/server/controller/RcvSysUserController.java +++ b/docus-recovery/src/main/java/com/docus/server/controller/RcvSysUserController.java @@ -1,14 +1,15 @@ package com.docus.server.controller; -import com.docus.infrastructure.shiro.ShiroUtil; import com.docus.infrastructure.web.request.SearchDTO; import com.docus.infrastructure.web.response.PageResult; import com.docus.server.api.recovery.RcvSysUserApi; +import com.docus.server.common.IgnoreValidate; import com.docus.server.dto.recovery.rcvsysuser.AddRcvSysUserDTO; import com.docus.server.dto.recovery.rcvsysuser.DeleteRcvSysUserDTO; import com.docus.server.dto.recovery.rcvsysuser.EditRcvSysUserDTO; import com.docus.server.dto.recovery.rcvsysuser.LoginRcvSysUserDTO; import com.docus.server.service.IRcvSysUserService; +import com.docus.server.vo.recovery.UserInfoView; import com.docus.server.vo.recovery.rcvsysuser.RcvSysUserVO; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; @@ -31,21 +32,22 @@ public class RcvSysUserController implements RcvSysUserApi { @Resource private IRcvSysUserService iRcvSysUserService; + @Override @ApiOperation("登录") - public void login(LoginRcvSysUserDTO userDTO) { - System.out.println("登录"); - iRcvSysUserService.doLogin(userDTO.getUserName(), userDTO.getUserPwd()); - ShiroUtil.setSessionAttr("USER_NAME", userDTO.getUserName()); - ShiroUtil.setSessionAttr("SESSION_PASSWORD", userDTO.getUserPwd()); + @IgnoreValidate + public UserInfoView login(LoginRcvSysUserDTO userDTO) { + String token = iRcvSysUserService.doLogin(userDTO.getUserName(), userDTO.getUserPwd()); + UserInfoView userInfoView = new UserInfoView(); + userInfoView.setToken(token); + return userInfoView; } @ApiOperation("退出登录") @Override - public void logout() { - ShiroUtil.removeSessionAttr("USER_NAME"); - ShiroUtil.removeSessionAttr("SESSION_PASSWORD"); - System.out.println("退出登录"); + @IgnoreValidate + public void logout(String token) { + iRcvSysUserService.logout(token); } /** diff --git a/docus-recovery/src/main/java/com/docus/server/service/IRcvSysUserService.java b/docus-recovery/src/main/java/com/docus/server/service/IRcvSysUserService.java index 3e91685..fb4c378 100644 --- a/docus-recovery/src/main/java/com/docus/server/service/IRcvSysUserService.java +++ b/docus-recovery/src/main/java/com/docus/server/service/IRcvSysUserService.java @@ -184,5 +184,7 @@ public interface IRcvSysUserService { */ int findByIdAndName(Serializable id, String name); - void doLogin(String userName, String userPwd); + String doLogin(String userName, String userPwd); + + void logout(String token); } diff --git a/docus-recovery/src/main/java/com/docus/server/service/impl/RcvSysUserServiceImpl.java b/docus-recovery/src/main/java/com/docus/server/service/impl/RcvSysUserServiceImpl.java index e667f7e..51d8b87 100644 --- a/docus-recovery/src/main/java/com/docus/server/service/impl/RcvSysUserServiceImpl.java +++ b/docus-recovery/src/main/java/com/docus/server/service/impl/RcvSysUserServiceImpl.java @@ -1,5 +1,6 @@ package com.docus.server.service.impl; +import com.docus.infrastructure.core.db.KeyGenerator; import com.docus.infrastructure.core.db.dao.IBaseDao; import com.docus.infrastructure.redis.service.IdService; import com.docus.infrastructure.shiro.ShiroUtil; @@ -7,6 +8,8 @@ import com.docus.infrastructure.web.exception.ApiException; import com.docus.infrastructure.web.exception.ExceptionCode; import com.docus.infrastructure.web.request.SearchDTO; import com.docus.infrastructure.web.response.PageResult; +import com.docus.server.common.RedisStringService; +import com.docus.server.constants.BusinessConstant; import com.docus.server.convert.RcvSysUserConvert; import com.docus.server.dto.recovery.rcvsysuser.AddRcvSysUserDTO; import com.docus.server.dto.recovery.rcvsysuser.DeleteRcvSysUserDTO; @@ -15,6 +18,7 @@ import com.docus.server.entity.recovery.RcvSysUser; import com.docus.server.enums.EffectiveEnum; import com.docus.server.infrastructure.dao.IRcvSysUserDao; import com.docus.server.service.IRcvSysUserService; +import com.docus.server.vo.recovery.UserInfoView; import com.docus.server.vo.recovery.rcvsysuser.RcvSysUserVO; import org.apache.commons.lang.StringUtils; import org.springframework.stereotype.Service; @@ -24,6 +28,7 @@ import javax.annotation.Resource; import java.io.Serializable; import java.util.Collection; import java.util.List; +import java.util.concurrent.TimeUnit; /** * 系统登录用户表 服务实现类 @@ -37,6 +42,8 @@ public class RcvSysUserServiceImpl implements IRcvSysUserService { private IRcvSysUserDao iRcvSysUserDao; @Resource private IdService idService; + @Resource + private RedisStringService redisStringService; /** * 按主键查询 @@ -326,7 +333,7 @@ public class RcvSysUserServiceImpl implements IRcvSysUserService { } @Override - public void doLogin(String userName, String userPwd) { + public String doLogin(String userName, String userPwd) { if (StringUtils.isBlank(userName) || StringUtils.isBlank(userPwd)) { throw new ApiException(ExceptionCode.ParamIllegal.getCode(), "用户名或密码不能为空!"); } @@ -341,6 +348,22 @@ public class RcvSysUserServiceImpl implements IRcvSysUserService { if (!user.getUserPwd().equals(md5Pwd)) { throw new ApiException(ExceptionCode.ParamIllegal.getCode(), "登录失败:密码错误!"); } + + + String token = KeyGenerator.genId(); + UserInfoView userInfoview = new UserInfoView(); + userInfoview.setToken(token); + userInfoview.setUserName(userName); + userInfoview.setPassword(userPwd); + redisStringService.setValue(BusinessConstant.REDIS_KEY_USER_TOKEN_PREFIX + token, userInfoview, 3, TimeUnit.MINUTES); + + return token; + } + + @Override + public void logout(String token) { + redisStringService.delete(BusinessConstant.REDIS_KEY_USER_TOKEN_PREFIX + token); + } }