欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

前后端分离实现登录拦截

程序员文章站 2022-03-15 11:42:17
...

一.认证方案

1.Session
利用Session我们可以管理用户状态:

  • 服务器接受第一个请求时候,生成session对象,并通过响应头告诉客户端在cookie中放入sessionId
  • 客户端之后发送请求时,会带上包含sessionId的cookie
  • 服务器通过sessionId获取session,进而得到当前的状态
  • 每次客户端访问服务端带上sessionId即可

2.客户端存储方案

特性 cookie localStorage sessionStorage
生命周期 一般由服务器生成,可设置失效时间。如果在浏览器端生成cookie,默认是关闭浏览器后失效 除非被清除,否则永久保存 仅在当前会话下有效,关闭页面或浏览器后被清除
数据大小 4K左右 一般为5MB 一般为5MB
通信方式 每次都会携带在HTTP头中,如果使用cookie保存过多数据会带来性能问题 仅在客户端(即浏览器)中保存,不参与和服务器的通信 同 localStorage

二.为什么需要前后端拦截

之前前端拦截的思路是:

  1. 判断的路径是否需要登录;如果需要,判断store里面有没有存储user信息
  2. store有放行,没有就要跳到登录页面

这样是不安全的,我们可以在控制台输入

window.localStorage.setItem('user', JSON.stringify({"name":"哈哈哈"}));

从而去伪造,访问任何一个页面了。
所以
要实现靠谱的拦截,由后端验证用户登录状态,前端带上sessionId发送请求交由后端认证。

三.前后端拦截

3.1后端拦截

默认情况下,跨域的cookie是被禁止的,需要两边都要设置。跨域情况下会先发出一个options请求试探,这个请求是不带cookie信息的,所以shiro无法获取到sessionId

public class LoginInterceptor  implements HandlerInterceptor{

    @Override
    public boolean preHandle (HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        // 放行 options 请求,否则无法让前端带上自定义的 header 信息,导致 sessionID 改变,shiro 验证失败
        if (HttpMethod.OPTIONS.toString().equals(httpServletRequest.getMethod())) {
            httpServletResponse.setStatus(HttpStatus.NO_CONTENT.value());
            return true;
        }

        Subject subject = SecurityUtils.getSubject();
        // 使用 shiro 验证
        if (!subject.isAuthenticated()) {
            return false;
        }
        return true;
    }

}
这里记录一下,我把这段代码屏蔽,也可以用。现在暂时不知道是什么原因。

SpringMVC配置允许跨域

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowCredentials(true)
                .allowedOrigins("http://localhost:8080")
                .allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE")
                .allowedHeaders("*")
    }

3.2前端拦截

在main.js加上

axios.defaults.withCredentials = true

为了防止伪造参数,绕过前端路由限制,在每个页面钱都向后端发送一个请求,目的是经由拦截器验证服务端的登录状态,防止上述情况的发生。

router.beforeEach((to, from, next) => {
    if (to.meta.requireAuth) {
      if (store.state.user) {
        axios.get('/authentication').then(resp => {
          if (resp.data) next()
        })
      } else {
        next({
          path: 'login',
          query: {redirect: to.fullPath}
        })
      }
    } else {
      next()
    }
  }
)

三.感谢

学习参考https://learner.blog.csdn.net/article/details/102788866