前后端分离应用——用户信息传递

本文介绍了在前后端分离的系统中,如何安全地传递用户信息。从单体应用到分布式应用,详细阐述了登录签发token的过程,以及在请求头中携带token进行鉴权的方法。在分布式环境下,通过Dubbo的Header交换机制解决了跨进程传递用户信息的问题。
摘要由CSDN通过智能技术生成

前言

记录前后端分离的系统应用下应用场景————用户信息传递

需求缘起

照例先看看web系统的一张经典架构图,这张图参考自网络:

在 Dubbo 自定义异常,你是怎么处理的? 中已经对该架构做了简单说明,这里不再描述。

简单描述下在该架构中用户信息(如userId)的传递方式

现在绝大多数的项目都是前后端分离的开发模式,采用token方式进行用户鉴权:

  • 客户端(pc,移动端,平板等)首次登录,服务端签发token,在token中放入用户信息(如userId)等返回给客户端
  • 客户端访问服务端接口,需要在头部携带token,跟表单一并提交到服务端
  • 服务端在web层统一解析token鉴权,同时取出用户信息(如userId)并继续向底层传递,传到服务层操作业务逻辑
  • 服务端在service层取到用户信息(如userId)后,执行相应的业务逻辑操作

问题:

为什么一定要把用户信息(如userId)藏在token中,服务端再解析token取出?直接登录后向客户端返回用户信息(如userId)不是更方便么?

跟用户强相关的信息是相当敏感的,一般用户信息(如userId)不会直接明文暴露给客户端,会带来风险。

单体应用下用户信息(如userId)的传递流程

什么是单体应用? 简要描述就是web层,service层全部在一个jvm进程中,更通俗的讲就是只有一个项目

登录签发 token

看看下面的登录接口伪代码:

web层接口:

    @Loggable(descp = "用户登录", include = "loginParam")
    @PostMapping("/login")
    public BaseResult<LoginVo> accountLogin(LoginParam loginParam) {
        return mAccountService.login(loginParam);
    }
复制代码

service层接口伪代码:

public BaseResult<LoginVo> login(LoginParam param) throws BaseException {
        //1.登录逻辑判断
        LoginVo loginVo = handleLogin(param);
        //2.签发token
        String subject = userId; 
        String jwt = JsonWebTokenUtil.issueJWT(UUID.randomUUID().toString(), subject,
                "token-server", BaseConstants.TOKEN_PERIOD_TIME, "", null, SignatureAlgorithm.HS512);
        loginVo.setJwt(jwt);
        return ResultUtil.success(loginVo);
    }
复制代码

注意到上述伪代码中,签发token时把userId放入客户标识subject中,签发到token中返回给客户端。这里使用的是JJWT生成的token

引入依赖:

        <!--jjwt-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.0</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.8.9</version>
        </dependency>
复制代码

相关工具类JsonWebTokenUtil

public class JsonWebTokenUtil {
    //秘钥
    public static final String SECRET_KEY = BaseConstant.SECRET_KEY;
    private static final ObjectMapper MAPPER = new ObjectMapper();
    private static CompressionCodecResolver codecResolver = new DefaultCompressionCodecResolver();
    
    //私有化构造
    private JsonWebTokenUtil() {
    }
    /* *
     * @Description  json web token 签发
     * @param id 令牌ID
     * @param subject 用户标识
     * @param issuer 签发人
     * @param period 有效时间(秒)
     * @param roles 访问主张-角色
     * @param permissions 访问主张-权限
     * @param algorithm 加密算法
     * @Return java.lang.String
     */
    public static String issueJWT(String id,String subject, String issuer, Long period,
                                  String roles, String permissions, SignatureAlgorithm algorithm) {
        // 当前时间戳
        Long currentTimeMillis = System.currentTimeMillis();
        // 秘钥
        byte[] secreKeyBytes = DatatypeConverter.parseBase64Binary(SECRET_KEY);
        JwtBuilder jwtBuilder = Jwts.builder();
        if (StringUtils.isNotBlank(id)) {
            jwtBuilder.setId(id);
        }
        if (StringUtils.isNotBlank(subject)) {
            jwtBuilder.setSubject(subject);
        }
        if (StringUtils.isNo
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值