SpringBoot+vue+token

前端
token验证
1、前端接受后台发过来的token,将其存入sessionStorage,并且在store.js中进行存储

 state: {
    // 存储token
    Authorization: sessionStorage.getItem('Authorization') ? sessionStorage.getItem('Authorization') : ''
  },
  mutations: {
    // 修改token,并将token存入localStorage
    changeLogin (state, user) {
      state.Authorization = user.Authorization;
      sessionStorage.setItem('Authorization', user.Authorization);
    },
    logout(state) {
      sessionStorage.removeItem('Authorization');
      sessionStorage.removeItem('user');

      state.token = null
    }
  },

2、路由守卫:将没有登录信息的访问请求全部转到login.vue,有相关信息则放行

router.beforeEach((to, from, next) => { // 路由跳转前监控(保证登录状态)
  // 重登陆删除本地数据
  if (to.path === '/login') {
    sessionStorage.removeItem('user')
  }
  let user = JSON.parse(sessionStorage.getItem('user'))
  // 登录验证:如果本地没有储存用户且不在登录页面则跳转
  if (!user && to.path !== '/login') {
    next({ path: '/login' })
  } else {
    next()
  }
})

3、配置请求头:这里使用axios,所以在axios的配置文件中添加:

axios.interceptors.request.use(
    config => {
      if (localStorage.getItem('Authorization')) {
        config.headers.Authorization = sessionStorage.getItem('Authorization');
      }
   
      return config;
    },
    error => {
      return Promise.reject(error);
    });

//http response 拦截器
axios.interceptors.response.use(
  response => {
      return response;
  },
  error => {
      if (error.response) {
          console.log(this);
          Vue.$store.commit("logout");
          Vue.$router.push({ path: "/login" });
      }
      return Promise.reject(error.response.data)
});

后端
token验证(集成jwt)
在pom.xml文件中导入相关依赖

      <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.4.0</version>
        </dependency>

生成token

@Service
public class TokenService {
    public String getToken(User user) {
        Date start = new Date();
        long currentTime = System.currentTimeMillis() + 60 * 60 * 1000;//一小时有效时间
        Date end = new Date(currentTime);
        String token = "";

        token = JWT.create().withAudience(user.getUid().toString()).withIssuedAt(start).withExpiresAt(end)
                .sign(Algorithm.HMAC256(user.getPassword()));
        return token;
    }
}

添加两个相关注解

//用来跳过验证的PassToken
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PassToken {
    boolean required() default true;
}

//需要登录才能进行操作的注解UserLoginToken
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface UserLoginToken {
    boolean required() default true;
}

添加一个拦截器判断访问该controller是否需要验证token

public class tokenInterceptor implements HandlerInterceptor {
        @Autowired
        UserService userService;

    /**
     *          预处理回调,判断每个处理器是否符合要求,返回true表示符合要求,放行
     *          这里主要是对user的id和password进行解密,如果要改变,还需要改变生成token的service
     * @param httpServletRequest
     * @param httpServletResponse
     * @param object
     *          拦截的对象
     * @return
     * @throws Exception
     */
        @Override
        public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {
            String token = httpServletRequest.getHeader("Authorization");// 从 http 请求头中取出 token
            // 如果不是映射到方法直接通过
            if(!(object instanceof HandlerMethod)){
                return true;
            }
            HandlerMethod handlerMethod=(HandlerMethod)object;
            Method method=handlerMethod.getMethod();
            //检查是否有passtoken注释,有则跳过认证
            if (method.isAnnotationPresent(PassToken.class)) {
                PassToken passToken = method.getAnnotation(PassToken.class);
                if (passToken.required()) {
                    return true;
                }
            }
            //检查有没有需要用户权限的注解
            if (method.isAnnotationPresent(UserLoginToken.class)) {
                UserLoginToken userLoginToken = method.getAnnotation(UserLoginToken.class);
                if (userLoginToken.required()) {
                    // 执行认证
                    if (token == null) {
                        throw new RuntimeException("无token,请重新登录");
                    }
                    // 获取 token 中的 user id
                    String userId;
                    try {
                        userId = JWT.decode(token).getAudience().get(0);
                    } catch (JWTDecodeException j) {
                        //jwt解码失败
                        throw new RuntimeException("401");
                    }
                        User user = userService.findUserById(userId);
                        if (user == null) {
                            throw new RuntimeException("用户不存在,请重新登录");
                        }
                        // 验证 token
                        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build();
                        try {
                            jwtVerifier.verify(token);
                        } catch (JWTVerificationException e) {
                            throw new RuntimeException("401");
                    }
                    //将验证通过后的用户信息放到请求中
                    httpServletRequest.setAttribute("currentUser", user);
                    return true;
                }
            }
            return true;
        }

    /**
     *         处理器执行之后,视图解析器渲染之前 执行的回调
     * @param httpServletRequest
     * @param httpServletResponse
     * @param o
     *         处理器执行后返回的数据
     * @param modelAndView
     * @throws Exception
     */
        @Override
        public void postHandle(HttpServletRequest httpServletRequest,
                               HttpServletResponse httpServletResponse,
                               Object o, ModelAndView modelAndView) throws Exception {

        }

    /**
     *          视图解析器将视图解析之后的回调
     * @param httpServletRequest
     * @param httpServletResponse
     * @param o
     * @param e
     * @throws Exception
     */
        @Override
        public void afterCompletion(HttpServletRequest httpServletRequest,
                                    HttpServletResponse httpServletResponse,
                                    Object o, Exception e) throws Exception {
        }

}

jwt的配置类

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
   @Override
   public void addInterceptors(InterceptorRegistry registry) {
       registry.addInterceptor(authenticationInterceptor())
               .addPathPatterns("/**");    // 拦截所有请求,通过判断是否有 @LoginRequired 注解 决定是否需要登录
   }
   @Bean
   public tokenInterceptor authenticationInterceptor() {
       return new tokenInterceptor();
   }
}	

使用
在controller中需要进行token验证的方法中添加@UserLoginToken

--------------------------------------分隔符
vue手动刷新页面,axios拦截器不执行情况

  1. 需求: vue里面的拦截器在每次请求前添加上token(Authorization)
  2. 问题:正常点击请求可以添加,一旦手动F5刷新页面,就直接没有进入拦截器,再次发送请求就恢复
  3. 分析原因: 需要把axios放外面单独封装,不放mian.js里面即可

src下面新建文件夹utils,文件名称intercept.js


import axios from 'axios'

axios.defaults.withCredentials = true
export const request = (config) => {
  return axios(config)
}

// 请求前设置header
axios.interceptors.request.use(
  config => {
    if (localStorage.getItem('Authorization')) {
      config.headers.Authorization = localStorage.getItem('Authorization')
    }

    return config
  },
  error => {
    return Promise.reject(error)
  })
// 请求完成后 拦截器
axios.interceptors.response.use(
  response => {
    console.log(response)
    if (response.data.code === 1003) {
      router.replace({
        path: '/login'
      })
      localStorage.removeItem('Authorization')
    }
    return response
  },
  error => {
    if (error.response) {
      switch (error.response.status) {
        case 401:
          localStorage.removeItem('Authorization')
          router.replace({
            path: '/login',
            query: {redirect: router.currentRoute.fullPath} // 登录成功后 跳转当前页面
          })
      }
    }
  }
)
// 这句一定要写
export default axios


然后在main.js引入,这里要注意import引入顺序,否则可能导致其他有问题。

你可能感兴趣的:(学习,spring)