Resolver Cache处理

This commit is contained in:
wangiegie@gmail.com 2017-12-22 12:56:08 +08:00
parent 178f85be9a
commit 69f20d3d8d
9 changed files with 129 additions and 19 deletions

View File

@ -44,7 +44,6 @@
<dependency> <dependency>
<groupId>com.zaxxer</groupId> <groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId> <artifactId>HikariCP</artifactId>
<!--<version>2.7.4</version>-->
</dependency> </dependency>
<!--myabtis-plus 代码生成依赖--> <!--myabtis-plus 代码生成依赖-->
<dependency> <dependency>

View File

@ -4,6 +4,7 @@ import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients; import org.springframework.cloud.netflix.feign.EnableFeignClients;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
/** /**
@ -16,6 +17,7 @@ import org.springframework.security.oauth2.config.annotation.web.configuration.E
@EnableResourceServer @EnableResourceServer
@EnableDiscoveryClient @EnableDiscoveryClient
@EnableFeignClients @EnableFeignClients
@ComponentScan(basePackages = {"com.github.pig.auth", "com.github.pig.common.bean"})
public class PigAuthServerApplication { public class PigAuthServerApplication {
public static void main(String[] args) { public static void main(String[] args) {

View File

@ -1,7 +1,10 @@
package com.github.pig.auth.controller; package com.github.pig.auth.controller;
import com.github.pig.common.constant.SecurityConstants;
import com.github.pig.common.util.R; import com.github.pig.common.util.R;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore; import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@ -32,6 +35,7 @@ public class UserController {
* @return true/false * @return true/false
*/ */
@PostMapping("/removeToken") @PostMapping("/removeToken")
@CacheEvict(value = SecurityConstants.TOKEN_USER_DETAIL, key = "#accesstoken")
public R<Boolean> removeToken(String accesstoken, String refreshToken) { public R<Boolean> removeToken(String accesstoken, String refreshToken) {
RedisTokenStore tokenStore = new RedisTokenStore(redisConnectionFactory); RedisTokenStore tokenStore = new RedisTokenStore(redisConnectionFactory);
tokenStore.removeRefreshToken(refreshToken); tokenStore.removeRefreshToken(refreshToken);

View File

@ -1,9 +1,11 @@
package com.github.pig.common.bean.aop; package com.github.pig.common.bean.aop;
import com.github.pig.common.constant.SecurityConstants;
import com.github.pig.common.util.R; import com.github.pig.common.util.R;
import com.github.pig.common.util.UserUtils; import com.github.pig.common.util.UserUtils;
import com.github.pig.common.util.exception.CheckException; import com.github.pig.common.util.exception.CheckException;
import com.github.pig.common.util.exception.UnloginException; import com.github.pig.common.util.exception.UnloginException;
import com.github.pig.common.vo.UserVo;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Around;
@ -11,12 +13,15 @@ import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.util.Arrays; import java.util.Arrays;
import java.util.Optional;
/** /**
* @author lengleng * @author lengleng
@ -28,6 +33,8 @@ import java.util.Arrays;
@Component @Component
public class ControllerAop { public class ControllerAop {
private static final Logger logger = LoggerFactory.getLogger(ControllerAop.class); private static final Logger logger = LoggerFactory.getLogger(ControllerAop.class);
@Autowired
private CacheManager cacheManager;
@Pointcut("execution(public com.github.pig.common.util.R *(..))") @Pointcut("execution(public com.github.pig.common.util.R *(..))")
public void pointCutR() { public void pointCutR() {
@ -65,10 +72,23 @@ public class ControllerAop {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest(); HttpServletRequest request = attributes.getRequest();
String username = UserUtils.getUserName(request);
if (StringUtils.isNotEmpty(username)) { String token = UserUtils.getToken(request);
UserVo userVo = null;
if (StringUtils.isNotEmpty(token)) {
userVo = cacheManager.getCache(SecurityConstants.TOKEN_USER_DETAIL).get(token, UserVo.class);
}
String username;
if (userVo == null) {
username = UserUtils.getUserName(request);
if (StringUtils.isNotEmpty(username)) {
UserUtils.setUser(username);
}
} else {
username = userVo.getUsername();
UserUtils.setUser(username); UserUtils.setUser(username);
} }
logger.info("Controller AOP get username:{}", username);
logger.info("URL : " + request.getRequestURL().toString()); logger.info("URL : " + request.getRequestURL().toString());
logger.info("HTTP_METHOD : " + request.getMethod()); logger.info("HTTP_METHOD : " + request.getMethod());
@ -79,7 +99,7 @@ public class ControllerAop {
Object result; Object result;
try { try {
result = pjp.proceed(); result = pjp.proceed();
logger.info(pjp.getSignature() + "use time:" + (System.currentTimeMillis() - startTime)); logger.info(pjp.getSignature() + "use time:" + (System.currentTimeMillis() - startTime));
} catch (Throwable e) { } catch (Throwable e) {
result = handlerException(pjp, e); result = handlerException(pjp, e);

View File

@ -1,6 +1,8 @@
package com.github.pig.common.bean.config; package com.github.pig.common.bean.config;
import com.github.pig.common.bean.resolver.TokenArgumentResolver; import com.github.pig.common.bean.resolver.TokenArgumentResolver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@ -14,8 +16,11 @@ import java.util.List;
*/ */
@Configuration @Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter { public class WebMvcConfig extends WebMvcConfigurerAdapter {
@Autowired
private CacheManager cacheManager;
@Override @Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) { public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new TokenArgumentResolver()); argumentResolvers.add(new TokenArgumentResolver(cacheManager));
} }
} }

View File

@ -1,5 +1,6 @@
package com.github.pig.common.bean.resolver; package com.github.pig.common.bean.resolver;
import com.github.pig.common.constant.SecurityConstants;
import com.github.pig.common.util.UserUtils; import com.github.pig.common.util.UserUtils;
import com.github.pig.common.vo.SysRole; import com.github.pig.common.vo.SysRole;
import com.github.pig.common.vo.UserVo; import com.github.pig.common.vo.UserVo;
@ -7,6 +8,7 @@ import com.xiaoleilu.hutool.util.CollectionUtil;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.core.MethodParameter; import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.bind.support.WebDataBinderFactory;
@ -17,6 +19,7 @@ import org.springframework.web.method.support.ModelAndViewContainer;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional;
/** /**
* @author lengleng * @author lengleng
@ -26,34 +29,70 @@ import java.util.List;
@Configuration @Configuration
public class TokenArgumentResolver implements HandlerMethodArgumentResolver { public class TokenArgumentResolver implements HandlerMethodArgumentResolver {
private Logger logger = LoggerFactory.getLogger(getClass()); private Logger logger = LoggerFactory.getLogger(getClass());
private CacheManager cacheManager;
public TokenArgumentResolver(CacheManager cacheManager) {
this.cacheManager = cacheManager;
}
/**
* 1. 入参筛选
*
* @param methodParameter 参数集合
* @return 格式化后的参数
*/
@Override @Override
public boolean supportsParameter(MethodParameter methodParameter) { public boolean supportsParameter(MethodParameter methodParameter) {
return methodParameter.getParameterType().equals(UserVo.class); return methodParameter.getParameterType().equals(UserVo.class);
} }
/**
* 1. 先从 cache 中判断token 是否已经有缓存
* 2. 不存在缓存情况解析token 获取用户信息
* 3. 不存在缓存情况在AOP进行缓存添加因为这里添加只会对入参含有 UserVo的生效而不是全局
*
* @param methodParameter 入参集合
* @param modelAndViewContainer model view
* @param nativeWebRequest web相关
* @param webDataBinderFactory 入参解析
* @return 包装对象
* @throws Exception exception
*/
@Override @Override
public Object resolveArgument(MethodParameter methodParameter, public Object resolveArgument(MethodParameter methodParameter,
ModelAndViewContainer modelAndViewContainer, ModelAndViewContainer modelAndViewContainer,
NativeWebRequest nativeWebRequest, NativeWebRequest nativeWebRequest,
WebDataBinderFactory webDataBinderFactory) throws Exception { WebDataBinderFactory webDataBinderFactory) throws Exception {
HttpServletRequest request = nativeWebRequest.getNativeRequest(HttpServletRequest.class); HttpServletRequest request = nativeWebRequest.getNativeRequest(HttpServletRequest.class);
String token = UserUtils.getToken(request);
if (StringUtils.isBlank(token)) {
logger.error("resolveArgument error token is empty");
return null;
}
Optional<UserVo> optional = Optional.ofNullable(cacheManager.getCache(SecurityConstants.TOKEN_USER_DETAIL).get(token, UserVo.class));
if (optional.isPresent()) {
logger.info("return cache user vo,token :{}", token);
return optional.get();
}
return optional.orElseGet(() -> generatorByToken(request, token));
}
private UserVo generatorByToken(HttpServletRequest request, String token) {
String username = UserUtils.getUserName(request); String username = UserUtils.getUserName(request);
List<String> roles = UserUtils.getRole(request); List<String> roles = UserUtils.getRole(request);
logger.info("Auth-Token-User:{}-Roles:{}", username, roles); logger.info("Auth-Token-User:{}-Roles:{}", username, roles);
UserVo userVo = new UserVo(); UserVo userVo = new UserVo();
if (StringUtils.isNotEmpty(username)) { userVo.setUsername(username);
userVo.setUsername(username); List<SysRole> sysRoleList = new ArrayList<>();
} for (String roleName : roles) {
if (CollectionUtil.isNotEmpty(roles)) { SysRole sysRole = new SysRole();
List<SysRole> sysRoleList = new ArrayList<>(); sysRole.setRoleName(roleName);
for (String roleName : roles) { sysRoleList.add(sysRole);
SysRole sysRole = new SysRole();
sysRole.setRoleName(roleName);
sysRoleList.add(sysRole);
}
userVo.setRoleList(sysRoleList);
} }
userVo.setRoleList(sysRoleList);
cacheManager.getCache(SecurityConstants.TOKEN_USER_DETAIL).put(token, userVo);
return userVo; return userVo;
} }
} }

View File

@ -65,4 +65,9 @@ public interface SecurityConstants {
* 验证码文字大小 * 验证码文字大小
*/ */
String DEFAULT_IMAGE_FONT_SIZE = "30"; String DEFAULT_IMAGE_FONT_SIZE = "30";
/**
* token-uservo
*/
String TOKEN_USER_DETAIL = "token-user-detail";
} }

View File

@ -74,22 +74,32 @@ public class UserUtils {
/** /**
* 根据请求heard中的token获取用户角色 * 根据请求heard中的token获取用户角色
* *
* @param httpServletRequest request
* @return 角色名 * @return 角色名
*/ */
public static List<String> getRole(HttpServletRequest httpServletRequest) { public static List<String> getRole(HttpServletRequest httpServletRequest) {
String authorization = httpServletRequest.getHeader(CommonConstant.REQ_HEADER); String token = getToken(httpServletRequest);
String token = StringUtils.substringAfter(authorization, CommonConstant.TOKEN_SPLIT);
String key = Base64.getEncoder().encodeToString(CommonConstant.SIGN_KEY.getBytes()); String key = Base64.getEncoder().encodeToString(CommonConstant.SIGN_KEY.getBytes());
Claims claims = Jwts.parser().setSigningKey(key).parseClaimsJws(token).getBody(); Claims claims = Jwts.parser().setSigningKey(key).parseClaimsJws(token).getBody();
List<String> roleNames = (List<String>) claims.get("authorities"); List<String> roleNames = (List<String>) claims.get("authorities");
return roleNames; return roleNames;
} }
/**
* 获取请求中token
*
* @param httpServletRequest request
* @return token
*/
public static String getToken(HttpServletRequest httpServletRequest) {
String authorization = httpServletRequest.getHeader(CommonConstant.REQ_HEADER);
return StringUtils.substringAfter(authorization, CommonConstant.TOKEN_SPLIT);
}
/** /**
* 设置用户信息 * 设置用户信息
* *
* @param username * @param username 用户名
*/ */
public static void setUser(String username) { public static void setUser(String username) {
THREAD_LOCAL_USER.set(username); THREAD_LOCAL_USER.set(username);

View File

@ -0,0 +1,26 @@
package com.github.pig.common.util;
import com.github.pig.common.constant.CommonConstant;
import org.apache.commons.lang.StringUtils;
import org.junit.Test;
import java.util.Optional;
/**
* @author lengleng
* @date 2017/12/22
*/
public class UserUtilsTest {
@Test
public void getToken() throws Exception {
String authorization = null;
System.out.println(StringUtils.substringAfter(authorization, CommonConstant.TOKEN_SPLIT));
}
@Test
public void optionalTest() {
Optional<String> optional = Optional.ofNullable("");
System.out.println(optional.isPresent());
}
}