专栏首页软件测试架构师俱乐部从0到1开发测试平台(十三)前后端接口token验证

从0到1开发测试平台(十三)前后端接口token验证

| 前言

前端登录成功之后,token会保存在浏览器的本地缓存里面,然后每次接口访问我们都会在header里面带上这个token,后台拿到这个token会去做用户认证,认证通过才会继续执行并成功返回,不通过提示用户验证失败或者请重新登录。前面我们的登录接口增加了token返回,并且保存前端把token进行了保存,但在接口请求的时候做token验证我们还没有做,接下来这篇文章讲的就是如何做token验证。

| 后端增加dao层对user_login表根据token查询

package com.caomingyu.cctestplatform.dao;

import com.caomingyu.cctestplatform.bean.UserLogin;
import org.apache.ibatis.annotations.Mapper;

import java.sql.Timestamp;

@Mapper
public interface UserLoginDao {
    UserLogin queryByToken(String token, Timestamp now);

}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.caomingyu.cctestplatform.dao.UserLoginDao">
    <resultMap id="userLogin" type="com.caomingyu.cctestplatform.bean.UserLogin">
        <result column="ID" property="id"/>
        <result column="USER_ID" property="userId"/>
        <result column="TOKEN" property="token"/>
        <result column="EXPIRATION_DATE" property="expirationDate"/>
        <result column="CREATE_DATE" property="createDate"/>
        <result column="LAST_UPDATE_DATE" property="lastUpdateDate"/>
        <result column="IS_VALID" property="isValid"/>
    </resultMap>
    <select id="queryByToken" resultMap="userLogin">
        select *
        from user_login
        where TOKEN = #{token}
        and EXPIRATION_DATE > #{now}
        and IS_VALID = 1
    </select>
</mapper>

| 后端增加后端登录拦截器,这样便可以在请求到后台时进行拦截,根据token查询登录表是否存在,不存在则提示请登录。

package com.caomingyu.cctestplatform.config;

import com.alibaba.fastjson.JSONObject;
import com.caomingyu.cctestplatform.bean.Result;
import com.caomingyu.cctestplatform.bean.UserLogin;
import com.caomingyu.cctestplatform.common.ResultType;
import com.caomingyu.cctestplatform.common.StatusCode;
import com.caomingyu.cctestplatform.dao.UserLoginDao;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.sql.Timestamp;
import java.util.Date;

@Component
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {

    @Autowired
    private UserLoginDao userLoginDao;
    /**
     * 预处理回调方法,实现处理器的预处理
     * 返回值:true表示继续流程;false表示流程中断,不会继续调用其他的拦截器或处理器
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        String token = request.getHeader("token");
        log.info("token:{}",token);
        //登录表里查下token是否存在
        UserLogin userLogin = userLoginDao.queryByToken(token, new Timestamp(new Date().getTime()));
        System.out.println("userLogin:" + userLogin);
        System.out.println("userLogin:" + request.getRequestURL());
        if (userLogin == null){
            //校验失败
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/json; charset=utf-8");
            response.setHeader("Access-Control-Allow-Headers", "token,content-type");
            response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
            Result result = Result.result(null,true, StatusCode.NEED_LOGIN, ResultType.NEED_LOGIN);
            response.getWriter().write(JSONObject.toJSONString(result));
            return false;
        }
        return true;
    }

    /**
     * 后处理回调方法,实现处理器(controller)的后处理,但在渲染视图之前
     * 此时我们可以通过modelAndView对模型数据进行处理或对视图进行处理
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) throws Exception {
        // TODO Auto-generated method stub

    }

    /**
     * 整个请求处理完毕回调方法,即在视图渲染完毕时回调,
     * 如性能监控中我们可以在此记录结束时间并输出消耗时间,
     * 还可以进行一些资源清理,类似于try-catch-finally中的finally,
     * 但仅调用处理器执行链中
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        // TODO Auto-generated method stub

    }
}

| 后端配置需要拦截校验token的接口地址

package com.caomingyu.cctestplatform.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.ArrayList;
import java.util.List;

/**
 * 和springmvc的webmvc拦截配置一样
 * @author BIANP
 */
@Configuration
public class WebConfigurer implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 拦截所有请求,通过判断是否有 @LoginRequired 注解 决定是否需要登录
        List<String> patternList = new ArrayList<>();
        patternList.add("/api/v1/user/login");
        registry.addInterceptor(LoginInterceptor()).addPathPatterns("/api/**").excludePathPatterns(patternList);
    }

    @Bean
    public LoginInterceptor LoginInterceptor() {
        return new LoginInterceptor();
    }
}

| 前端main.js添加请求拦截器,设置config.headers.common['token']的值,便会对请求都默认带上token

//添加一个请求拦截器
axios.interceptors.request.use(function (config) {
  config.headers.common['token'] = window.sessionStorage.getItem('token');
  return config;
}, function (error) {
  // Do something with request error
  console.info("error: ");
  console.info(error);
  return Promise.reject(error);
});

| 补充

vue本地存储的几种方式的简单介绍和区别(sessionStorage、localStorage以及vuex)

sessionStorage 方法针对一个 session 进行数据存储。当用户关闭浏览器窗口后,数据会被删除。

localStorage 方法存储的数据没有时间限制。第二天、第二周或下一年之后,数据依然可用。

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

区别:vuex存储在内存,localstorage(本地存储)则以文件的方式存储在本地,永久保存;sessionstorage( 会话存储 ) ,临时保存。localStorage和sessionStorage只能存储字符串类型,对于复杂的对象可以使用ECMAScript提供的JSON对象的stringify和parse来处理

应用场景:vuex用于组件之间的传值,localstorage,sessionstorage则主要用于不同页面之间的传值。

永久性:当刷新页面(这里的刷新页面指的是 --> F5刷新,属于清除内存了)时vuex存储的值会丢失,sessionstorage页面关闭后就清除掉了,localstorage不会。

注:很多同学觉得用localstorage可以代替vuex, 对于不变的数据确实可以,但是当两个组件共用一个数据源(对象或数组)时,如果其中一个组件改变了该数据源,希望另一个组件响应该变化时,localstorage,sessionstorage无法做到,原因就是上面所说的区别。

本文分享自微信公众号 - 软件测试架构师俱乐部(gh_03227f9a322f),作者:瑺圊樹

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-09-05

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 从0到1开发测试平台(十)后端增加登录token返回

    Token是服务端生成的一串字符串,以作客户端进行请求的一个令牌,当第一次登录后,服务器生成一个Token便将此Token返回给客户端,以后客户端只需带上这个T...

    cctester
  • 从0到1开发测试平台(四)Controller+Service +Dao三层的功能划分

    DAO只完成增删改查,虽然可以1-n,n-n,1-1关联,模糊、动态、子查询都可以。但是无论多么复杂的查询,dao只是封装增删改查。至于增删改查如何去实现一个功...

    cctester
  • Python 魔法方法之__getattr__(self,name)

    当实例对象调用一个不存在的属性时,系统通常会报错,那有啥办法避免这种现象么,或者说自定义报错信息,答案是肯定的,我们可以通过定义__getattr__(self...

    cctester
  • SpringBoot thymeleaf自定义错误页面

    憧憬博客
  • Jsonp

    方案一:在Controller中取cookie中的token数据,调用sso服务查询用户信息。

    用户5927264
  • SpringBoot入门建站全系列(十二)Spring Security使用token做认证

    Spring 是一个非常流行和成功的 Java 应用开发框架。Spring Security 基于 Spring 框架,提供了一套 Web 应用安全性的完整解决...

    品茗IT
  • ssh登录实现

    工程目录 ? 配置文件详解 Spring的applicationContext.xml文件 <span ><?xml version="1.0" encodin...

    用户1141560
  • java之spring之整合ssh

    github地址:https://github.com/Vincent-yuan/spring_ssh

    Vincent-yuan
  • 利用python wxpy和requests写一个自动应答微信机器人实例

    在做测试的过程中,同事们经常需要获取一个账户的token和个人信息,我自己利用spring boot写了一个接口,但是对于APP测试同学来说不是很方便,因为需要...

    FunTester
  • SpringBoot中集成jwt实现前后端分离的token验证机制

    Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安...

    你好戴先生

扫码关注云+社区

领取腾讯云代金券