精华内容
下载资源
问答
  • 前端路由的基本原理、使用 history 路由模式时后端登录拦截器的配置、Vuex 的引入以及前端拦截器的实现。

    前言

    这一篇主要讲前端路由与登录拦截器的实现。放在一起讲是因为我在开发登录拦截器时因为这个路由的问题遇到了很多坑,花费了很长时间,网上的解决方案都不怎么靠谱,综合了好几种办法才最终成功,其实关于这个部分能写两三篇文章,名字起好了还能多很多访问量,不过为了保证文章的质量我没有这么做,毕竟我不是大神,如果再不用点心,写出来的文章自己都不想再看第二遍,更别提能对大家有所帮助了。

    一、前端路由

    大家如果留心观察就会发现,之前我们做的页面的 URL 里有一个 # 号,这个 # 号有什么含义呢?

    假设在 html 中有这么一段代码:<div id="test">This is a test</div>,如果我们想让页面定位到这个 div 所在的位置,可以加一个超链接 <a herf="#test">Jump to test</a>,这里的 # 被称为“锚点”,点击超链接,可以发现网页的 URL 发生了变化,但页面并不会跳转。

    在互联网流量如此庞大的今天,我们需要想办法后端服务器的压力,利用 AJAX,我们可以不重载页面就刷新数据,如果再加上 # 号的特性(即改变 URL 却不请求后端),我们就可以在前端实现页面的整体变化,而不用每次都去请求后端。

    为了实现前端路由,我们可以监听 # 号后面内容的变化(hashChange),从而动态改变页面内容。URL 的 # 号后面的地址被称为 hash ,估计是哪个大神拍脑袋想的,不用深究。这种实现方式我们称之为 Hash 模式,是非常典型的前端路由方式。

    另一种常用的方式被称为 History 模式,这种方式使用了 History APIHistory API 顾名思义就是针对历史记录的 API ,这种模式的原理是先把页面的状态保存到一个对象(state)里,当页面的 URL 变化时找到对应的对象,从而还原这个页面。其实原本人家这个功能是为了方便浏览器前进后退的,不得不说程序员们的脑洞真大。使用了这种模式,就可以摆脱 # 号实现前端路由。

    Vue 已经为我们提供了两种模式的前端路由,无需我们自己去实现。

    二、使用 History 模式

    首先我们把 Vue 中配置的路由从默认的 hash 模式切换为 histroy 模式。打开我们的前端项目 wj-vue,修改 router\index.js,加入 mode: 'history 这句话。整体代码如下:

    import Vue from 'vue'
    import Router from 'vue-router'
    import AppIndex from '@/components/home/AppIndex'
    import Login from '@/components/Login'
    
    Vue.use(Router)
    
    export default new Router({
      mode: 'history',
      routes: [
        {
          path: '/login',
          name: 'Login',
          component: Login
        },
        {
          path: '/index',
          name: 'AppIndex',
          component: AppIndex
        }
      ]
    })
    

    运行项目,访问不加 # 号的 http://localhost:8080/login ,成功加载页面。

    接下来,我们把前端打包后部署在后端。这不是前后端分离项目推荐的做法,之前我们讲过其实应该把前后端分别部署在不同的服务器中,但实际上仍有不少项目会选择把前后端整合在一起,只使用一个服务器,所以这里我们也提及一下这种方式,但在之后的开发中不会这样部署。

    先在项目目录执行 npm run build,控制台输出如下内容表明执行完毕:
    在这里插入图片描述
    这时在项目的 dist 文件夹下生成了 static 文件夹和 index.html 文件,把这两个文件,拷贝到我们后端项目的 wj\src\main\resources\static 文件夹下,一定要注意这个位置,这时后端配置的静态文件的 path,虽然看起来很诡异,但一般都不作修改。
    在这里插入图片描述
    接下来,打开后端项目并运行,访问 http://localhost:8443/index.html ,(注意输入后缀 .html)发现页面是空白的,但确实取到了这个页面,再访问 http://localhost:8443/login ,发现跳转到了错误页面(White Error Page)。
    在这里插入图片描述
    这里我们回顾一下单页面应用的概念,在我们这个项目中,其实只有 index.html 这一个页面,所有的其它内容都是在这个页面里动态渲染的。当我们直接在后端访问 /login 路径时,服务器会后端并没有这个路径对应的内容,所以返回了 Error Page。

    为了获取到我们需要的内容,我们要想办法触发前端路由,即在后端添加处理内容,把 通过这个 URL 渲染出的 index.html 返回到浏览器。

    在后端项目中新建一个 package 名为 error,新建实现 ErrorPageRegistrar 接口的类 ErrorConfig,把默认的错误页面设置为 /index.html,代码如下

    package com.evan.wj.error;
    
    import org.springframework.boot.web.server.ErrorPageRegistrar;
    import org.springframework.boot.web.server.ErrorPage;
    import org.springframework.boot.web.server.ErrorPageRegistry;
    import org.springframework.http.HttpStatus;
    import org.springframework.stereotype.Component;
    
    @Component
    public class ErrorConfig implements ErrorPageRegistrar {
    
        @Override
        public void registerErrorPages(ErrorPageRegistry registry) {
            ErrorPage error404Page = new ErrorPage(HttpStatus.NOT_FOUND, "/index.html");
            registry.addErrorPages(error404Page);
        }
    
    }
    

    重新启动项目,访问 http://localhost:8443/login ,成功进入登录页面。

    三、后端登录拦截器

    为了完善登录功能,我们需要限制未登录状态下对核心功能页面的访问。登录拦截可以由多种方式来实现,我们首先讲解后端拦截器的开发。(注意如果没有把前后端项目整合起来,就没有办法使用这种方式)

    一个简单拦截器的逻辑如下:

    1.用户访问 URL,检测是否为登录页面,如果是登录页面则不拦截
    2.如果用户访问的不是登录页面,检测用户是否已登录,如果未登录则跳转到登录页面

    1.LoginController

    首先我们修改 LoginController 的内容。之前我们实现了通过查询数据库验证用户名是否正确,但仅此而已。

    为了保存登录状态,我们可以把用户信息存在 Session 对象中(当用户在应用程序的 Web 页之间跳转时,存储在 Session 对象中的变量不会丢失),这样在访问别的页面时,可以通过判断是否存在用户变量来判断用户是否登录。这是一种比较简单的方式,感兴趣的同学可以尝试别的方法。

    修改后的代码内容如下:

    package com.evan.wj.controller;
    
    import com.evan.wj.pojo.User;
    import com.evan.wj.result.Result;
    import com.evan.wj.service.UserService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.*;
    import org.springframework.web.util.HtmlUtils;
    
    import javax.servlet.http.HttpSession;
    
    @Controller
    public class LoginController {
    
        @Autowired
        UserService userService;
    
        @CrossOrigin
        @PostMapping(value = "/api/login")
        @ResponseBody
        public Result login(@RequestBody User requestUser, HttpSession session) {
            String username = requestUser.getUsername();
            username = HtmlUtils.htmlEscape(username);
    
            User user = userService.get(username, requestUser.getPassword());
            if (null == user) {
                return new Result(400);
            } else {
                session.setAttribute("user", user);
                return new Result(200);
            }
        }
    }
    
    

    其实只是添加了一条语句 session.setAttribute("user", user);

    2.LoginInterceptor

    新建 package 名为 interceptor,新建类 LoginInterceptor

    Interceptor 即拦截器,在 Springboot 我们可以直接继承拦截器的接口,然后实现 preHandle 方法。preHandle 方法里的代码会在访问需要拦截的页面时执行。

    代码如下:

    package com.evan.wj.interceptor;
    
    import com.evan.wj.pojo.User;
    import org.apache.commons.lang.StringUtils;
    import org.springframework.web.servlet.HandlerInterceptor;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;
    
    public class LoginInterceptor  implements HandlerInterceptor{
    
        @Override
        public boolean preHandle (HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
            HttpSession session = httpServletRequest.getSession();
            String contextPath=session.getServletContext().getContextPath();
            String[] requireAuthPages = new String[]{
                    "index",
            };
    
            String uri = httpServletRequest.getRequestURI();
    
            uri = StringUtils.remove(uri, contextPath+"/");
            String page = uri;
    
            if(begingWith(page, requireAuthPages)){
                User user = (User) session.getAttribute("user");
                if(user==null) {
                    httpServletResponse.sendRedirect("login");
                    return false;
                }
            }
            return true;
        }
    
        private boolean begingWith(String page, String[] requiredAuthPages) {
            boolean result = false;
            for (String requiredAuthPage : requiredAuthPages) {
                if(StringUtils.startsWith(page, requiredAuthPage)) {
                    result = true;
                    break;
                }
            }
            return result;
        }
    }
    
    

    看起来似乎比较长,其实就是判断 session 中是否存在 user 属性,如果存在就放行,如果不存在就跳转到 login 页面。这里使用了一个路径列表(requireAuthPages),可以在里面写下需要拦截的路径。当然我们也可以拦截所有路径,那样就不用写这么多了,但会有逻辑上的问题,就是你访问了 \login 页面,仍然会需要跳转,这样就会引发多次重定向问题。

    3.WebConfigurer

    我们写完了拦截器,但是它却并不会生效,因为我们还没有把它配置到项目中。

    新建 package 名为 config,新建类 MyWebConfigurer,代码如下:

    package com.evan.wj.config;
    
    import com.evan.wj.interceptor.LoginInterceptor;
    import org.springframework.boot.SpringBootConfiguration;
    import org.springframework.context.annotation.Bean;
    import org.springframework.web.servlet.config.annotation.*;
    
    @SpringBootConfiguration
    public class MyWebConfigurer implements WebMvcConfigurer {
    
        @Bean
        public LoginInterceptor getLoginIntercepter() {
            return new LoginInterceptor();
        }
    
        @Override
        public void addInterceptors(InterceptorRegistry registry){
            registry.addInterceptor(getLoginIntercepter()).addPathPatterns("/**").excludePathPatterns("/index.html");
        }
    }
    
    

    通过这个配置类,我们添加了之前写好的拦截器。这里有一句非常重要的语句,即

    registry.addInterceptor(getLoginIntercepter()).addPathPatterns("/**").excludePathPatterns("/index.html");
    

    这条语句的作用是对所有路径应用拦截器,除了 /index.html

    之前我们在拦截器 LoginInterceptor 中配置的路径,即 index,触发的时机是在拦截器生效之后。也就是说,我们访问一个 URL,会首先通过 Configurer 判断是否需要拦截,如果需要,才会触发拦截器 LoginInterceptor,根据我们自定义的规则进行再次判断。

    /index/index.html 是不同的,也就是说 /index 会触发拦截器而 /index.html 不会,但根据拦截器 LoginInterceptor 中我们定义的判断条件,以 /index 开头的路径都会被转发,包括 index.html

    因为我们做的是单页面应用,之前通过配置 ErrorPage,实际上访问所有路径都会重定向到 /index.html 。我们直接在浏览器地址栏输入 /index 会触发拦截器,经过拦截器重定向到 /login,然后 /login 再经过 Configurer 的判断,再次触发拦截器,由于不在需要拦截的路径中,所以被放行,页面则重新定向到了 /index.html,如果没有再 Configurer 中取消对 /index.html 的拦截,则会再次触发拦截器,再次重定向到 /login,引发如下错误。
    在这里插入图片描述
    上述过程比较绕,这是我开发时的失误,但我觉得恰好可以帮助大家理解拦截器与单页面应用,所以保留了下来。

    4.效果检验

    运行后端项目,访问 http://localhost:8443/index ,发现页面自动跳转到了 http://localhost:8443/login ,输入用户名和密码登录,跳转到 http://localhost:8443/index , 这时可以把浏览器标签关掉,再在一个新标签页输入 http://localhost:8443/index ,发现不会被拦截。

    四、Vuex 与前端登录拦截器

    前面我们使用了后端拦截器,但这种拦截器只有在将前后端项目整合在一起时才能生效,而前后端分离的项目实际上不推荐这么做,接下来我们尝试用前端实现相似的功能。

    实现前端登录器,需要在前端判断用户的登录状态。我们可以像之前那样在组件的 data 中设置一个状态标志,但登录状态应该被视为一个全局属性,而不应该只写在某一组件中。所以我们需要引入一个新的工具——Vuex,它是专门为 Vue 开发的状态管理方案,我们可以把需要在各个组件中传递使用的变量、方法定义在这里。之前我一直没有使用它,所以在不同组件传值的问题上十分头疼,要写很多多余的代码来调用不同组件的值,所以推荐大家从一开始就去熟悉这种管理方式。

    1.引入 Vuex

    在我们的项目文件夹中,运行 npm install vuex --save,之后,在 src 目录下新建一个文件夹 store,并在该目录下新建 index.js 文件,在该文件中引入 vue 和 vuex,代码如下:

    import Vue from 'vue'
    import Vuex from 'vuex'
    
    Vue.use(Vuex)
    

    之后,我们在 index.js 里设置我们需要的状态变量和方法。为了实现登录拦截器,我们需要一个记录用户信息的变量。为了方便日后的扩展(权限认证等),我们使用一个用户对象而不是仅仅使用一个布尔变量。同时,设置一个方法,触发这个方法时可以为我们的用户对象赋值。完整的代码如下:

    import Vue from 'vue'
    import Vuex from 'vuex'
    
    Vue.use(Vuex)
    
    export default new Vuex.Store({
      state: {
        user: {
          username: window.localStorage.getItem('user' || '[]') == null ? '' : JSON.parse(window.localStorage.getItem('user' || '[]')).username
        }
      },
      mutations: {
        login (state, user) {
          state.user = user
          window.localStorage.setItem('user', JSON.stringify(user))
        }
      }
    })
    

    这里我们还用到了 localStorage,即本地存储,在项目打开的时候会判断本地存储中是否有 user 这个对象存在,如果存在就取出来并获得 username 的值,否则则把 username 设置为空。这样我们只要不清除缓存,登录的状态就会一直保存。

    2.修改路由配置

    为了区分页面是否需要拦截,我们需要修改一下 src\router\index.js,在需要拦截的路由中加一条元数据,设置一个 requireAuth 字段如下:

        {
          path: '/index',
          name: 'AppIndex',
          component: AppIndex,
          meta: {
            requireAuth: true
          }
        }
    

    完整的 index.js 代码如下:

    import Vue from 'vue'
    import Router from 'vue-router'
    import AppIndex from '@/components/home/AppIndex'
    import Login from '@/components/Login'
    
    Vue.use(Router)
    
    export default new Router({
      mode: 'history',
      routes: [
        {
          path: '/login',
          name: 'Login',
          component: Login
        },
        {
          path: '/index',
          name: 'AppIndex',
          component: AppIndex,
          meta: {
            requireAuth: true
          }
        }
      ]
    })
    
    

    3.使用钩子函数判断是否拦截

    钩子函数及在某些时机会被调用的函数。这里我们使用 router.beforeEach(),意思是在访问每一个路由前调用。

    打开 src\main.js ,首先添加对 store 的引用

    import store from './store'
    

    并修改 Vue 对象里的内容

    new Vue({
      el: '#app',
      render: h => h(App),
      router,
      // 注意这里
      store,
      components: { App },
      template: '<App/>'
    })
    

    接着写 beforeEach() 函数

    router.beforeEach((to, from, next) => {
        if (to.meta.requireAuth) {
          if (store.state.user.username) {
            next()
          } else {
            next({
              path: 'login',
              query: {redirect: to.fullPath}
            })
          }
        } else {
          next()
        }
      }
    )
    

    这个的逻辑很简单,首先判断访问的路径是否需要登录,如果需要,判断 store 里有没有存储 user 的信息,如果存在,则放行,否则跳转到登录页面,并存储访问的页面路径(以便在登录后跳转到访问页)。

    完整的 main.js 代码如下:

    import Vue from 'vue'
    import App from './App'
    import router from './router'
    import store from './store'
    import ElementUI from 'element-ui'
    import 'element-ui/lib/theme-chalk/index.css'
    
    var axios = require('axios')
    axios.defaults.baseURL = 'http://localhost:8443/api'
    Vue.prototype.$axios = axios
    Vue.config.productionTip = false
    
    Vue.use(ElementUI)
    
    router.beforeEach((to, from, next) => {
        if (to.meta.requireAuth) {
          if (store.state.user.username) {
            next()
          } else {
            next({
              path: 'login',
              query: {redirect: to.fullPath}
            })
          }
        } else {
          next()
        }
      }
    )
    
    /* eslint-disable no-new */
    new Vue({
      el: '#app',
      render: h => h(App),
      router,
      store,
      components: { App },
      template: '<App/>'
    })
    
    

    4.修改 Login.vue

    之前的登录组件中,我们只是判断后端返回的状态码,如果是 200,就重定向到首页。在经过前面的配置后,我们需要修改一下登录逻辑,以最终实现登录拦截。

    修改后的逻辑如下:

    1.点击登录按钮,向后端发送数据
    2.受到后端返回的成功代码时,触发 store 中的 login() 方法,把 loginForm 对象传递给 store 中的 user 对象
    (*这里只是简单的实现,在后端我们可以通过用户名和密码查询数据库,获得 user 表的完整信息,比如用户昵称、用户级别等,返回前端,并传递给 user 对象,以实现更复杂的功能)
    3.获取登录前页面的路径并跳转,如果该路径不存在,则跳转到首页

    修改后的 login() 方法如下:

    login () {
      var _this = this
      console.log(this.$store.state)
      this.$axios
        .post('/login', {
          username: this.loginForm.username,
          password: this.loginForm.password
        })
        .then(successResponse => {
          if (successResponse.data.code === 200) {
            // var data = this.loginForm
            _this.$store.commit('login', _this.loginForm)
            var path = this.$route.query.redirect
            this.$router.replace({path: path === '/' || path === undefined ? '/index' : path})
          }
        })
        .catch(failResponse => {
        })
    }
    

    完整的 Login.vue 代码如下:

    <template>
      <body id="poster">
        <el-form class="login-container" label-position="left"
                 label-width="0px">
          <h3 class="login_title">系统登录</h3>
          <el-form-item>
            <el-input type="text" v-model="loginForm.username"
                      auto-complete="off" placeholder="账号"></el-input>
          </el-form-item>
          <el-form-item>
            <el-input type="password" v-model="loginForm.password"
                      auto-complete="off" placeholder="密码"></el-input>
          </el-form-item>
          <el-form-item style="width: 100%">
            <el-button type="primary" style="width: 100%;background: #505458;border: none" v-on:click="login">登录</el-button>
          </el-form-item>
        </el-form>
      </body>
    </template>
    
    <script>
    
      export default {
        name: 'Login',
        data () {
          return {
            loginForm: {
              username: 'admin',
              password: '123'
            },
            responseResult: []
          }
        },
        methods: {
          login () {
            var _this = this
            console.log(this.$store.state)
            this.$axios
              .post('/login', {
                username: this.loginForm.username,
                password: this.loginForm.password
              })
              .then(successResponse => {
                if (successResponse.data.code === 200) {
                  // var data = this.loginForm
                  _this.$store.commit('login', _this.loginForm)
                  var path = this.$route.query.redirect
                  this.$router.replace({path: path === '/' || path === undefined ? '/index' : path})
                }
              })
              .catch(failResponse => {
              })
          }
        }
      }
    </script>
    
    <style>
      #poster {
        background:url("../assets/eva.jpg") no-repeat;
        background-position: center;
        height: 100%;
        width: 100%;
        background-size: cover;
        position: fixed;
      }
      body{
        margin: 0px;
      }
      .login-container {
        border-radius: 15px;
        background-clip: padding-box;
        margin: 90px auto;
        width: 350px;
        padding: 35px 35px 15px 35px;
        background: #fff;
        border: 1px solid #eaeaea;
        box-shadow: 0 0 25px #cac6c6;
      }
      .login_title {
        margin: 0px auto 40px auto;
        text-align: center;
        color: #505458;
      }
    
    </style>
    
    

    5.效果检验

    同时运行前后端项目,访问 http://localhost:8080/index ,发现页面直接跳转到了 http://localhost:8080/login?redirect=%2Findex

    在这里插入图片描述
    输入账号密码后登录,成功跳转到 http://localhost:8080/index ,之后再次访问则无需登录(除非清除缓存)。


    最后吐槽两句,人呐,真是不能乱立 flag,写第一篇文章的时候,我说感谢老板不让我 996,然后就 895 了,上一篇文章我说这两天闲,多写几篇文章,然后就又接了个大项目,周末还在出差开会,昨天晚上忙到 12 点困得不行,想着先睡觉早上早点起来再把工作收个尾,结果酒店隔壁房间一群小孩儿在玩狼人杀,回想起我们过去同样的行径,这口气我忍了。。。

    所以读者大人们请原谅我没有及时更新,作为一个不知名博主,十分感谢大家的支持。我会坚持下去的,希望大家都能坚持做自己想做的事,一起变得更加牛批!

    查看系列文章目录:
    https://learner.blog.csdn.net/article/details/88925013

    上一篇:Vue + Spring Boot 项目实战(五):使用 Element 辅助前端开发

    下一篇: Vue + Spring Boot 项目实战(七):导航栏与图书页面设计

    展开全文
  • vue实现登录拦截

    2020-10-15 04:45:31
    主要介绍了vue实现登录拦截
  • 主要介绍了SpringBoot拦截器实现登录拦截的方法示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
  • 本文通过实例代码给大家介绍了vue+axios 前端实现登录拦截的方法,主要通过路由拦截和http拦截,具体实例代码大家跟随小编一起通过本文学习吧
  • 登录拦截

    2013-03-11 23:53:33
    使用spring+struts2+hibernate实现简单的登录拦截器。实现登录。用户注销功能。单表增删查实现分页功能
  • vue 登录拦截

    2020-12-19 11:33:59
    vue登录拦截 1、什么是登录拦截登录拦截就是在用户没有登录之前就阻止用户访问其他的页面,就只有当用户完成登录后才可以访问其他的界面。 2、路由拦截 ​ vue组件化的开发就是使用vue-router进行页面跳转的,...

    vue登录拦截

    1、什么是登录拦截

    ​ 登录拦截就是在用户没有登录之前就阻止用户访问其他的页面,就只有当用户完成登录后才可以访问其他的界面。

    2、路由拦截

    ​ vue组件化的开发就是使用vue-router进行页面跳转的,所以登录拦截需要处理一下路由,让用户在没有登录成功之前一直处于登录界面。就算用户在地址栏进行输入地址也会直接返回登录界面。

    2.1定义路由(加入meta属性)

    ​ 我们在定义路由的时候,在meta属性中存放一个属性来判断该路由是否需要检查(如果为true,那就需要检查,在满足条件是才可以跳转到该路由)。

    //例子中使用requireAuth来表示是否需要检查
    //router.js 配置路由的文件
    //引入路由
    import Vue from 'vue';
    import Router from "vue-router"
    Vue.use(Router);
    
    const originalPush = Router.prototype.push
    Router.prototype.push = function push(location) {
    	return originalPush.call(this, location).catch(err => err)
    }
    
    import Login from ' ' //一个路径
    import Index from ' ' //一个路径
    
    let router = new Router({
    	mode: 'history',
    	routes: [
            //首先写一个登录界面的路由,登录界面不需要检查,那么这里就暂时不要meta属性了
            {
    			path: '/login',
    			name: 'Login',
    			component: Login,
    		},{
    			path: '/',
    			name: '/',
    			redirect: '/login',
    			//redirect   表示当路径使用到‘/’是,就自动跳转到路径为‘/login’
    		},
            //因为我们需要为index界面设置登录拦截,那么需要加上
            {
    			path: '/index',
    			name: 'Index',
    			component: Index,
    			meta: {
    				requireAuth: true
    			},
    		},
    	]
    })
    
    export default router
    
    2.2添加登录拦截

    在JavaScript中有两个属性:sessionStoragelocalStorage
    sessionStoragelocalStorage都是可以将数据保存下来,sessionStorage是会话存储,数据保留至关闭当前页面,刷新是不会丢失数据的;localStorage是本地存储,数据会一直保留,除非手动删除该数据。
    一般来说,sessionStorage可以用于保存token(就是后台做的安全,用户需要先登录,拿到token后才能获取其他数据),而localStorage可以用于记住密码,将密码保留在本地,之后就不用再输入密码了。

    用法:

    sessionStorage.setItem('isLogin',true)  //这表示存储一个名为isLogin的值为true的数据
    sessionStorage.getItem('isLogin')  //这表示获取存储的名为isLogin的值
    
    localStorage.setItem('isLogin',true)  //这表示存储一个名为isLogin的值为true的数据
    localStorage.getItem('isLogin')  //这表示获取存储的名为isLogin的值
    //用法都比较相似
    

    好,下面进入正题:
    我们可以利用 sessionStorage 将值或者状态存入浏览器,
    例如,sessionStorage.setItem(‘isLogin’,1) , 这表示向浏览器中存储一个名为isLogin的值为1的数据。
    我们再来写登录拦截:

    //还是在router.js中 我们这里就放在 export default router 的后面
    //登录拦截
    router.beforeEach((to, from, next) => {
        if (to.meta.requireAuth) {  // 判断该路由是否需要登录权限
            //如果需要就执行下面的代码
            
            var num=sessionStorage.getItem("isLogin");
            // 通过sessionStorage 获取当前的isLogin的值 将我们保存的isLogin的值赋给num,num是顺便取的名称,可以换
            //我们在登录界面,我们使用请求,请求成功后,我们就使用sessionStorage为‘isLogin’保存一个值  1,如果请求失败,就不保存‘isLogin’的值
            //如果请求成功,num的值就是1,请求失败就是null,所以下面进行判断
            if (num==1) {  
                //如果登录了,就跳转到'/index'路径
                next({path:'/index'});
            }
    		else {
                next({
                    path: '/login',//返回登录界面
                    // query: {redirect: to.fullPath}  
                })
            }
        }
        else {
            //如果不需要登录权限就直接跳转到该路由
            next();
        }
    })
    

    3、例子

    上面我们将登录拦截写好了,现在来写一个简单的例子来试一下:

    //先来一个登录界面 login.vue
    //这里不需要请求,所以我们来一个简单的就行了
    <template>
    	<div>
    		<button @click="LOGIN">登录按钮</button>
    	</div>
    </template>
    
    <script>
    	export default {
    		data() {
    			return {
    			
    			}
    		},
    		methods:{
    			LOGIN(){
    				sessionStorage.setItem('isLogin',1);
    			}
    		}
    	}
    </script>
    
    //再来一个主页 index.vue
    //就显示一点文本就要可以了
    <template>
    	<div>
    		登录成功,欢迎进入主页
    	</div>
    </template>
    

    注意:现在可以把上面index.js中的引入组件的路径给补充完整,简单再App.vue中加上的中加上不然组件不会渲染出来,如果不懂,可以先去看看vue-router,vue-router官网地址。在试的时候,可以先在浏览器的地址栏直接在地址后面加上/index,就像http://127.0.0.1/index,因为没有登录,所以会直接返回登录界面。

    4、结尾

    到此登录拦截就完成了,我自认为写的比较详细,但是如果不懂可以直接问。当然,如果有什么不对的地方,请一定要指正。谢谢。

    展开全文
  • SpringBoot拦截器实现登录拦截

    万次阅读 多人点赞 2019-07-12 22:27:29
    SpringBoot拦截器可以做什么 可以对URL路径进行拦截,...SpringBoot拦截器实现登录拦截 pom.xml: <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmln...
    • 源码

    GitHub:https://github.com/291685399/springboot-learning/tree/master/springboot-interceptor01

    • SpringBoot拦截器可以做什么

    可以对URL路径进行拦截,可以用于权限验证、解决乱码、操作日志记录、性能监控、异常处理等

    • SpringBoot拦截器实现登录拦截

    pom.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.0.0.RELEASE</version>
            <relativePath/>
        </parent>
        <groupId>com.wyj</groupId>
        <artifactId>springboot-interceptor01</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>springboot-interceptor01</name>
        <description>springboot拦截器</description>
    
        <properties>
            <java.version>1.8</java.version>
        </properties>
    
        <dependencies>
            <!-- springboot -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
                <scope>runtime</scope>
                <optional>true</optional>
            </dependency>
    
            <!-- lombok -->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
    
            <!-- thymeleaf -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-thymeleaf</artifactId>
            </dependency>
        </dependencies>
    
        <build>
            <finalName>springboot-interceptor01</finalName>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    </project>
    

    WebMvcConfigurer:继承WebMvcConfigurationSupport类,重写addInterceptors方法

    /**
     * 在springboot2.0.0之后,WebMvcConfigurerAdapter已经过时了
     * 会使用WebMvcConfigurer或者WebMvcConfigurationSupport替代
     *
     * @author wyj
     * @create 2019-06-01 21:48
     */
    @Configuration
    public class WebMvcConfigurer extends WebMvcConfigurationSupport {
    
        /**
         * 在springboot2.0.0之前继承WebMvcConfigurerAdapter类,重写addInterceptors方法
         *
         * @param registry
         */
    //    @Override
    //    public void addInterceptors(InterceptorRegistry registry) {
    //        /**
    //         * 拦截器按照顺序执行,如果不同拦截器拦截存在相同的URL,前面的拦截器会执行,后面的拦截器将不执行
    //         */
    //        registry.addInterceptor(new AuthorityInterceptor())
    //                .addPathPatterns("/user/**");
    //        super.addInterceptors(registry);
    //    }
    
        /**
         * 在springboot2.0.0之后实现WebMvcConfigurer接口,重写addInterceptors方法
         *
         * @param registry
         */
    //    @Override
    //    public void addInterceptors(InterceptorRegistry registry) {
    //        /**
    //         * 拦截器按照顺序执行,如果不同拦截器拦截存在相同的URL,前面的拦截器会执行,后面的拦截器将不执行
    //         */
    //        registry.addInterceptor(new AuthorityInterceptor())
    //                .addPathPatterns("/user/**");
    //    }
    
        /**
         * 在springboot2.0.0之后继承WebMvcConfigurationSupport类,重写addInterceptors方法
         *
         * @param registry
         */
        @Override
        protected void addInterceptors(InterceptorRegistry registry) {
            /**
             * 拦截器按照顺序执行,如果不同拦截器拦截存在相同的URL,前面的拦截器会执行,后面的拦截器将不执行
             */
            registry.addInterceptor(new AuthorityInterceptor())
                    .addPathPatterns("/user/**");
            super.addInterceptors(registry);
        }
    }
    

    AuthorityInterceptor:实现HandlerInterceptor接口,重写preHandlepostHandleafterCompletion方法

    preHandle:在请求处理之前进行调用(Controller方法调用之前)
    postHandle:请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)
    afterCompletion:在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)

    @Slf4j
    public class AuthorityInterceptor implements HandlerInterceptor {
    
        private static final Set<String> NOT_INTERCEPT_URI = new HashSet<>();//不拦截的URI
    
        static {
            NOT_INTERCEPT_URI.add("/user/login.html");
            NOT_INTERCEPT_URI.add("/user/login");
        }
    
        /**
         * 在请求处理之前进行调用(Controller方法调用之前)
         */
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
                                 Object object) throws Exception {
            String uri = request.getRequestURI();
            if (NOT_INTERCEPT_URI.contains(uri)) {
                log.info("不拦截" + uri);
                return true;
            }
            log.info("拦截" + uri);
            HttpSession session = request.getSession();
            UserInfo userInfo = (UserInfo) session.getAttribute("user_info_in_the_session");
            if (userInfo == null) {
                throw new RuntimeException("用户未登陆");
            }
            return true;
        }
    
        /**
         * 请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)
         */
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object object, ModelAndView mv) throws Exception {
        }
    
        /**
         * 在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行
         * (主要是用于进行资源清理工作)
         */
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object object, Exception ex) throws Exception {
        }
    }
    

    UserController

    @Controller
    @RequestMapping(value = "/user")
    public class UserController {
    
        @RequestMapping(value = "/login.html")
        public String index() {
            return "login";
        }
    
        @RequestMapping(value = "/login")
        public String login(User user) {
            //查询数据库,我这里直接写死
            User dbUser = new User(1, "zhangsan", "123456", "admin");
            if (dbUser.getPassword().equals(user.getPassword())) {
                UserInfo userInfo = new UserInfo(dbUser.getId(), dbUser.getUsername(), dbUser.getRole());
                HttpSession session = getRequest().getSession();
                session.setAttribute("user_info_in_the_session", userInfo);
                return "admin";
            }
            return "login";
        }
    
        @RequestMapping(value = "/userInfo")
        @ResponseBody
        public String userInfo() {
            HttpSession session = getRequest().getSession();
            UserInfo userInfo = (UserInfo) session.getAttribute("user_info_in_the_session");
            return userInfo.toString();
        }
    
        private HttpServletRequest getRequest() {
            return ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
        }
    }
    

    User:

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class User implements Serializable {
    
        private int id;
        private String username;
        private String password;
        private String role;
    
    }
    

    UserInfo: 用于存在用户信息储存在session中

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class UserInfo implements Serializable {
    
        private int id;
        private String username; 
        private String role;
    
    }
    

    login.html:只是一个很简单的登录表单

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>登陆页面</title>
    </head>
    <body>
    <form action="/user/login" method="post">
        登陆:<br/>
        用户名:<input name="username" id="username" type="text"/><br/>&nbsp;&nbsp;&nbsp;码:<input name="password" id="password" type="password"/><br/>
        <input type="submit" value="登陆"/>
    </form>
    </body>
    </html>
    

    admin.html:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>首页</title>
    </head>
    <body>
    <form action="/user/userInfo" method="get">
        <input type="submit" value="用户信息"/></form>
    </body>
    </html>
    
    展开全文
  • 主要介绍了vue-resource请求实现http登录拦截或者路由拦截的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • 主要介绍了Vue登录拦截 登录后继续跳转指定页面的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
  • 主要介绍了springboot+springmvc实现登录拦截,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • 编写登录拦截器(类需要实现HandlerInterceptor) /** * DESC : 登录拦截器 * @author Lonely * */ public class AppInterceptor implements HandlerInterceptor{ @Override public void afterCompletion...
  • 阅读本篇之前,可以先提前了解小编在之前写过的登录拦截的那篇博客。有助于更好的理解本篇权限拦截。 二.权限拦截思路解析:获取用户访问路径uri 1.首先遍历所有的权限判断其中是否包含该uri,如果不包含则不需要...

    权限拦截

    思路解析

    一.阅读本篇之前,可以先提前了解小编在之前写过的登录拦截的那篇博客。有助于更好的理解本篇权限拦截。
    二.权限拦截思路解析:获取用户访问路径uri
    1.首先遍历所有的权限判断其中是否包含该uri,如果不包含则不需要拦截(比如:userController/login )比如这个登录方法的路径访问时就不需要拦截,即我们只拦截所有权限里的路径,因此在数据库编写路权限径时注意区分大小写,及不能漏掉要拦截的权限路径。如果包含则需要判断该用户是否有对应权限。
    2.当所有的权限包含该uri时,判断该用户的权限列表是否有对应权限。如有则说明该用户访问的路径他有权利去访问和之后的相关操作,不需要拦截。如果用户权限列表没有该uri说明用户不具备此权限,需要拦截该用户。
    3.当需要拦截该用户时,就和登录拦截很相似,需要判断是不是ajax请求并返回相应提示信息给用户。

    准备工作

    如上所述,权限拦截需要如下“工具”:
    1.permissionListAll 所有的权限列表

    public List<Permission> queryPermissionList() {
    		return permissionRepository.findAll();
    	}
    

    通过JpaRepository接口自带的查询方法查出所有权限列表。

    2.permissionListByUserId 用户的权限列表

    @Query(nativeQuery = true,value = "select DISTINCT tp.* FROM t_user_role_new tur LEFT JOIN t_role_permission_new trp ON tur.roleId = trp.roleId LEFT JOIN t_permission_new tp on trp.permissionId = tp.id where tur.userId = ?1")
    	List<Permission> findPermissionListByUserId(Integer userId);
    

    为了提高性能小编是通过三表联查获得用户权限:通过用户id查询,用户_角色关联表左联角色_权限关联表左联权限表,通过三表联查查询到该用户id对应的所有权限。

    3.String uri = request.getRequestURI(); 用户访问的地址栏路径。(URI,统一资源标志符(Uniform Resource Identifier, URI),表示的是web上每一种可用的资源,如 HTML文档、图像、视频片段、程序等都由一个URI进行定位的。)

    具体实现

    新建一个PermissionInterceptor基础HandlerInterceptorAdapter并重写preHandle方法。

    package com.fh.interceptor;
    
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;
    
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
    
    import com.fh.model.Permission;
    import com.fh.util.JsonUtil;
    
    public class PermissionInterceptor extends HandlerInterceptorAdapter{
    
    	@SuppressWarnings("unchecked")
    	@Override
    	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
    			throws Exception {
    		HttpSession session = request.getSession();
    		/*
    		 * 登陆成功后login方法已经将permissionListByUserId,
    		 * permissionListAll放入session里,所以我们只需要从session中取出即可
    		 */
    		List<Permission> permissionListByUserId = (List<Permission>) session.getAttribute("permissionListByUserId");
    		List<Permission> permissionListAll = (List<Permission>) session.getAttribute("permissionListAll");
    		
    		String uri = request.getRequestURI();// 类似于userController/addUser
    		
    		if(StringUtils.isBlank(uri)) {//如果uri为空则不需要拦截
    			return true;
    		}
    		boolean contains = false;
    		/*
    		 * 立一个flag(contains) 若flag(contains)为true表明所有权限包含该uri,
    		 * 一旦包含即可break提高代码性能。
    		 */
    		if(permissionListAll != null && permissionListAll.size() > 0) {
    			for (Permission permission : permissionListAll) {
    				if(StringUtils.isNotBlank(permission.getUrl()) && uri.contains(permission.getUrl())) {
    					contains = true;
    					break;
    				}
    			}
    		}
    		if(contains == false) {//若flag(contains)为false表明所有权限列表如果不包含则不需要拦截
    			return true;
    		}else {//表明所有权限permissionListAll包含该uri,就需要进一步验证用户权限是否包含
    			boolean hasPermission = false;
    			/*
    			 * 当所有的权限包含该uri时,判断该用户的权限列表是否有对应权限。
    			 * 如有则说明该用户访问的路径他有权利去访问和之后的相关操作,不需要拦截。
    			 * 如果用户权限列表没有该uri说明用户不具备此权限,需要拦截该用户。
    			 * 
    			 */
    			if(permissionListByUserId != null && permissionListByUserId.size() > 0) {
    				for (Permission permission : permissionListByUserId) {
    					if(StringUtils.isNotBlank(permission.getUrl()) && uri.contains(permission.getUrl())) {
    						hasPermission = true;
    						break;
    					}
    				}
    			}
    			if(hasPermission == true) {//在permissionListAll里边,且有用户权限。允许用户访问。
    				return true;
    			}else {//用户权限列表没有该uri说明用户不具备此权限,需要拦截该用户
    				String header = request.getHeader("X-Requested-With");
    				//根据请求头部判断是不是ajax请求
    				if(StringUtils.isNotBlank(header) && header.equals("XMLHttpRequest")) {
    					//是ajax请求就要给前端页面一个信号,在前端页面判断后可以再弹出提示信息,跳到指定页面
    					Map<String, Object> result = new HashMap<String, Object>();
    					result.put("code", 2000);
    					JsonUtil.outJson(response, result);
    				}else {//不是ajax请求可以直接重定向到指定页面
    					response.sendRedirect(request.getServletContext().getContextPath()+"/no-permission.jsp");
    				}
    				return false;
    			}
    		}
    		
    	}
    }
    
    

    springMVC.xml配置

    <mvc:interceptor>
    				<mvc:mapping path="/**" />
    				/*
    				*配置白名单,放开静态资源
    				*/
    				<mvc:exclude-mapping path="/js/**" />
    				<mvc:exclude-mapping path="/bootstrap/**" />
    				
    				<bean class="com.fh.interceptor.PermissionInterceptor"></bean>
    </mvc:interceptor> 
    

    写在最后

    本篇为小编和人理解所作,如有错误请联系小编进行修改或删除。

    展开全文
  • JAVA登录拦截器,查看用户是否登录过,未登录禁止访问页面
  • 登录拦截器(通用版)

    2017-08-01 13:42:23
    登录拦截器(通用版)
  • 主要介绍了Spring MVC实现的登录拦截器代码分享,涉及拦截器的简单介绍,拦截器和过滤器的区以及拦截器实现代码等相关内容,这里分享给大家,供需要的朋友参考。
  • 利用拦截器和自定义注解实现未登录拦截实现思路自定义注解拦截器代码实现拦截器加入配置其它微服务中引用使用该登录权限校验代码实现 实现思路 所有需要有登录权限的接口先校验是否已登录(登录成功会往redis缓存中...
  • 登录拦截逻辑 第一步:路由拦截 首先在定义路由的时候就需要多添加一个自定义字段requireAuth,用于判断该路由的访问是否需要登录。如果用户已经登录,则顺利进入路由, 否则就进入登录页面。 const routes = ...
  • 基于Arouter的登录拦截
  • struts2登录拦截(拦截Action,拦截url)
  • struts登录拦截器问题

    2015-12-18 09:19:23
    问题:登录之后跳转到一个jsp页面,该页面上通过跳转时被登录拦截器拦截。 我想问的是,明明已经登录之后再跳转的,为什么会被登录拦截器拦截呢?刚开始接触这一块,不是很懂,希望能尽快得到大神们的帮助,谢谢谢谢...
  • 本篇文章主要介绍了Express+Nodejs 下的登录拦截实现代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • 主要介绍了SpringBoot登录拦截配置详解(实测可用),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
  • Interceptor登录拦截(Spring拦截器)

    千次阅读 2017-12-23 21:48:06
    Interceptor登录拦截 拦截器HandlerInterceptor接口有三个回调方法 1.preHandle方法,顾名思义,该方法将在请求处理之前进行调用。SpringMVC 中的Interceptor 是链式的调用的,在一个应用中或者说是在一个请求中...
  • Cookies自动登录、权限控制、未登录拦截,是一个完整的登录实例,整理源于网络
  • spring 登录拦截

    千次阅读 2016-06-08 21:16:50
    登录拦截器可以拦截普通请求和ajax请求,并将原请求跳转至登录页面 1、dispatcher-servlet.xml 2、LoginInterceptor.java package com.common.interceptor; import javax.servlet....
  • 用户的登录拦截

    千次阅读 2019-06-12 16:12:18
    首先我们得找到登录的backLogin,jsp页面 然后我们在做一个拦截器 用户登录了就放行 用户没有登录就拦截 LoginFilter 现在我们回到UserServlet进行操作 ...做登录拦截比较难的就是什么你该拦什么你不该拦 ...
  • vue 登录拦截及权限管理

    千次阅读 2020-02-27 16:43:15
    登录拦截 用户登录成功后服务端返回token的值,然后前端使用axios中请求拦截器(service.interceptors.request.use)再每个的请求接口上加上Authorization:token的值,服务端通过这个Authorization来获取token的值...
  • Springboot 拦截器配置(登录拦截

    千次阅读 2019-09-29 03:23:23
    Springboot 拦截器配置(登录拦截) 注意这里环境为springboot为2.1版本 1.编写拦截器实现类,实现接口 HandlerInterceptor, 重写里面需要的三个比较常用的方法,实现自己的业务逻辑代码 (就是自己拦截器拦截...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 117,025
精华内容 46,810
关键字:

登录拦截