分布式Session解决方案_Token + JWT

接上一篇:分布式6大核心专题_分布式Session
https://gblfy.blog.csdn.net/article/details/113802195

实现流程
1.引入JWT组件
2.依赖+代码(拦截器+注册拦截器+常量)+配置
3.演示同一程序启动8081端口和8082端口模拟2个服务器分布式
4.调用8081登录接口
5.调用8081获取用户信息接口
6.调用8082获取用户信息接口

1. 引入JWT组件
   <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.10.3</version>
        </dependency>
2. 代码+配置

application.yml

server:
  port: 8081 #应用web端口

package com.gblfy.distributed.session.controller;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.gblfy.distributed.session.consts.Const;
import org.springframework.web.bind.annotation.*;

import java.util.Date;

@RequestMapping("/user")
@RestController
public class UserController {

    @GetMapping("/loginWithJwt")
    public String loginWithJwt(@RequestParam String username,
                               @RequestParam String password) {
        Algorithm algorithm = Algorithm.HMAC256(Const.JWT_KEY);
        String token = JWT.create()
                .withClaim(Const.LOGIN_USER, username)
                .withClaim(Const.UID, 1)
                .withExpiresAt(new Date(System.currentTimeMillis() + 3600000))
                .sign(algorithm);
        return token;
    }

    @GetMapping("/infoWithJwt")
    public String infoWithJwt(@RequestAttribute String login_user) {
        return login_user;
    }
}

登录拦截器

package com.gblfy.distributed.session.intercepter;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.gblfy.distributed.session.consts.Const;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class LoginIntercepter extends HandlerInterceptorAdapter {

    /**
     * 返回true, 表示不拦截,继续往下执行
     * 返回false/抛出异常,不再往下执行
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String token = request.getHeader(Const.JWT_TOKEN);
        if (StringUtils.isEmpty(token)) {
            throw new RuntimeException("token为空");
        }

        Algorithm algorithm = Algorithm.HMAC256(Const.JWT_KEY);
        JWTVerifier verifier = JWT.require(algorithm)
                .build(); //Reusable verifier instance
        try {
            DecodedJWT jwt = verifier.verify(token);
            request.setAttribute(Const.UID, jwt.getClaim(Const.UID).asInt());
            request.setAttribute(Const.LOGIN_USER, jwt.getClaim(Const.LOGIN_USER).asString());
        }catch (TokenExpiredException e) {
            //token过期
            throw new RuntimeException("token过期");
        }catch (JWTDecodeException e) {
            //解码失败,token错误
            throw new RuntimeException("解码失败,token错误");
        }

        return true;
    }
}

注册拦截器

package com.gblfy.distributed.session.config;

import com.gblfy.distributed.session.intercepter.LoginIntercepter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Autowired
    private LoginIntercepter loginIntercepter;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {

        registry.addInterceptor(loginIntercepter)
                .addPathPatterns("/user/**")   //未登录的都会被拦截
               .excludePathPatterns("/user/login");
    }
}

Const常量

package com.gblfy.distributed.session.consts;

public class Const {

    public static final String JWT_KEY = "gblfy";
    public static final String JWT_TOKEN = "token";
    public static final String UID = "uid";
    public static final String LOGIN_USER = "login_user";
}

3. 分别启动8081端口和8082端口

同上一篇

4. 调用8081登录接口
#登录接口
http://localhost:8081/user/loginWithJwt?username=admin&password=admin
5. 调用8081获取用户信息接口
#获取用户信息接口
http://localhost:8081/user/infoWithJwt?token=登录后的token

注:由于需要在请求header添加token,因此,请使用postman工具测试

6. 调用8082获取用户信息接口
#获取用户信息接口
http://localhost:8082/user/infoWithJwt?token=登录后的token

注:由于需要在请求header添加token,因此,请使用postman工具测试

补充1:
小伙伴发现,只有登陆成功后,携带token才可以访问其他接口,对吧!但是,每次都要手动填写token是不是很麻烦,其实正常的场景,前端会将登录后的token存放到Local Storage中,访问接口时会携带token,后端也会校验此token是否合法。

补充2:
拦截器可以定义多个,比如请求前日志记录拦截器等等,还有就是拦截器异常建议采用自定义异常返回前端比较友好,这里为了方便抛出运行时异常。

相关推荐
©️2020 CSDN 皮肤主题: 猿与汪的秘密 设计师:白松林 返回首页