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; 

}

内部服务明文传输的安全性

微服务内部基于内网服务器之间的数据交互,这个根据具体的行业来决定怎么处理,是否需要做加密 ,多不涉密的行业明文传输即可。

外部服务都会有防火墙,网关不会有太多的业务逻辑,用户也不可能绕过网关直接调用内部服务 。

以上根据个人能力随笔发挥。。。

来源: 雨林博客(www.yl-blog.com)