SpringCloud服务内部的会话传递与解析
先说说会话机制
主流的用户会话保持技术包含以下:
– cookie
– session
– token
在微服务模式下,使用更多的是采用token机制来保持用户会话。而具体的实现会采用jwt来实现token,这样用户的会话数据会分布到用户端也不用服务器存储,但是他会消耗计算性能(jwt需要做签名校验)这里注意一定不要将敏感数据存储到jwt中,因为Base64解码后它是明文的。
SpringCloud网关
网关在收到请求后,接收用户的token,将token转义为服务内部可识别的用户信息。
例如:
token=MKLDNSLKDNLSADJASDLKDJKSA5312dfasd
通过Redis查询到用户的基本信息
{
"userId": 1,
"roles":[
"ADMIN", "MEMBER"
]
}
网关将转发解析后 的用户数据通过HTTP请求头转发到具体调用的服务。这样被调用的服务就能通过请求头得到那串JSON数据。从而得到 用户的ID甚至更多的用户信息。
具体的内部服务获取用户信息实现
这里可以使用注解 ,通过Spring的参数拦截转换请求头的json数据为具体控制器的参数。
/**
* 获取用户信息
*/
@GetMapping("/info")
public Result info(@JwtUser Session session) {
MerchantUserInfoVO vo = merchantSellerService.getUserInfoByUserId(session.getUserId());
if (vo == null)
return Result.fail(SystemErrorType.ACCOUNT_NOT_FOUND);
return Result.success(vo);
}
自定义注解代码
import java.lang.annotation.*;
/**
* JWT获取登录用户注解
*
* @author marker
* @create 2018-05-28 14:06
**/
@Documented
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface JwtUser {
String value() default "";
}
拦截带JWTUSER注解的 请求参数
import com.alibaba.fastjson.JSON;
import com.springboot.cloud.common.core.annotation.JwtUser;
import com.springboot.cloud.common.core.entity.session.SessionUser;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import javax.servlet.http.HttpServletRequest;
import static com.springboot.common.web.interceptor.UserInterceptor.X_CLIENT_TOKEN_USER;
/**
* Jwt User参数解析器
*
* @author marker
* @create 2018-05-28 14:08
**/
@Slf4j
@ControllerAdvice
public class JwtUserHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
if (parameter.hasParameterAnnotation(JwtUser.class)) {
log.debug("JwtUserHandlerMethodArgumentResolver");
return true;
}
return false;
}
@Override
public Object resolveArgument(MethodParameter parameter,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) throws Exception {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
.currentRequestAttributes()).getRequest();
// 获取如果为空设置默认值
String authorization = StringUtils.defaultIfBlank(request.getHeader(X_CLIENT_TOKEN_USER), "{}");
// 转换为对象
SessionUser sessionUser = JSON.parseObject(authorization, SessionUser.class);
return sessionUser;
}
}
Session 实体
import java.io.Serializable;
public class Session implements Serializable {
private Long userId;
private String userName;
private String client_id;
}
内部服务明文传输的安全性
微服务内部基于内网服务器之间的数据交互,这个根据具体的行业来决定怎么处理,是否需要做加密 ,多不涉密的行业明文传输即可。
外部服务都会有防火墙,网关不会有太多的业务逻辑,用户也不可能绕过网关直接调用内部服务 。
以上根据个人能力随笔发挥。。。