1.Token的使用

客户端使用用户名跟密码请求登录
服务端收到请求,去验证用户名与密码
验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端
客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者 Local Storage 里
客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据
APP登录的时候发送加密的用户名和密码到服务器,服务器验证用户名和密码,如果成功,以某种方式比如随机生成32位的字符串作为token,存储到服务器中,并返回token到APP,以后APP请求时
凡是需要验证的地方都要带上该token,然后服务器端验证token,成功返回所需要的结果,失败返回错误信息,让他重新登录。其中服务器上token设置一个有效期,每次APP请求的时候都验证token和有效期
Token 都需要设有效期。根据系统的安全需要,尽可能的短

2.使用JWT生成并校验Token

2.1.JWT简介

通俗地说,JWT的本质就是一个字符串**,它是将用户信息保存到一个Json字符串中,然后进行编码后得到一个JWT token,**并且这个JWT token带有签名信息,接收后可以校验是否被篡改,所以可以用于在各方之间安全地将信息作为Json对象传输。

2.2 .JWT的结构

JWT由3部分组成:标头(Header)、有效载荷(Payload)和签名(Signature)。在传输的时候,会将JWT的3部分分别进行Base64编码后用.进行连接形成最终传输的字符串

3.使用JWT

3.1引入依赖

<!-- JWT -->
		<dependency>
			<groupId>com.auth0</groupId>
			<artifactId>java-jwt</artifactId>
			<version>3.10.3</version>
		</dependency>

3.2.创建TokenUtils,用于生成Token

public  static  String getToken(User user){
        String token = JWT.create().withAudience(user.getId().toString())//基于JWT创建Token并将user的id存在Token
                       .withExpiresAt(DateUtil.offsetHour(new Date(),2))//两个小时以后Token过期
                       .sign(Algorithm.HMAC256(user.getPassword()));//以password作为token的密钥
        return  token;
    }

3.3.User实体类添加Token字段,用于登录用户携带token

给实体类添加上反馈前端的字段token

@TableField(exist = false)//只为了前端和后端的验证,该字段不加在数据库表里面
    private String token;

登录的方法里面从前面编写的TokenUtils中获取生成的token,存储到返回前端的user里面

//userService登录的时候携带token存到user对象  
public User login(User loginUser) {
        // TODO Auto-generated method stub
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", loginUser.getUsername()).eq("password", loginUser.getPassword());
        List<User> list = userMapper.selectList(queryWrapper);
        if(list.size()==0) {
            return null;
        }
        else {
           User user =  list.get(0);
            String token = TokenUtils.getToken(user);
            user.setToken(token);
            return user;
        }

    }

3.4.前端拿到token,设置请求后端时候请求头携带token

// request 拦截器
// 可以自请求发送前对请求做一些处理
// 比如统一加token,对请求参数统一加密
request.interceptors.request.use(config => {
    config.headers['Content-Type'] = 'application/json;charset=utf-8';
    const user = SessionStorage.get("user");
    if(user){
        config.headers['token'] = user.token;
    }
    return config
}, error => {
    return Promise.reject(error)
});

3.5.后端创建JWT拦截器,验证token

 @Autowired
    private UserService userService;
    /**
     * 拦截器的前置方法,返回true代表放行
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //获取请求头中的token
        String token = request.getHeader("token");
        //如果请求的不是处理器的方法直接通过,(拦截controller)
        if(!(handler instanceof HandlerMethod)){
            return true;
        }
        //如果token为空白字符串,则抛出异常(判断token是否存在)CustomException是自定义异常类
        if(StrUtil.isBlank(token)){
            throw new CustomException(401,"无token,请重新登录");
        }
        //获取token中的id
        String strUserId;
        try {
            strUserId = JWT.decode(token).getAudience().get(0);
        }catch (Exception e){
            throw new CustomException(401,"token验证失败,请重新登录");
        }

        //从token获取id后查询
        User user = userService.getById(Integer.parseInt(strUserId));
        if (user==null) {
            throw new CustomException(401, "用户不存在,请重新登录");
        }

        // 用户密码加密验证
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build();
        try {
            jwtVerifier.verify(token);
        }catch (Exception e){
            throw new CustomException(401, "token验证失败,请重新登录");
        }

        //如果以上代码都没有发生异常则放行
        return true;

    }

3.6.配置JWT拦截器的配置类,设置拦截规则和放行规则

@Override
	public void addInterceptors(InterceptorRegistry registry) {

//添加自定义的拦截器JWTInterceptor

		registry.addInterceptor(this.jwtInterceptor())

				.addPathPatterns("/**")// 拦截所有请求

				.excludePathPatterns(" /user/login", " /file/**", "/**/importExl", "/*/export");

	}

//将jwt拦截器对象交给spring管理

	@Bean

	public JWTInterceptor jwtInterceptor() {

		return new JWTInterceptor();

	}
Logo

前往低代码交流专区

更多推荐