前后端完全分离实现登录和退出

前后端分离的整合

使用springsecurity+前端项目+redis完成认证授权的代码

1. 搭建一个前端工程

使用 vue ui搭建,使用webstrom操作

2. 创建一个登录页面

<template><div class="login_container"><!-- 登录盒子  --><div class="login_box"><!-- 头像 --><div class="avatar_box"><img src="../assets/3.jpg" alt=""></div><!-- 登录表单 --><el-form :model="loginForm" ref="LoginFormRef"  label-width="0px" class="login_form"><!-- 用户名 --><el-form-item prop="username"><el-input v-model="loginForm.username" prefix-icon="el-icon-user-solid" ></el-input></el-form-item><!-- 密码 --><el-form-item prop="password"><el-input type="password" v-model="loginForm.password" prefix-icon="el-icon-s-grid"></el-input></el-form-item><!-- 按钮 --><el-form-item class="btns"><el-button type="primary" >登录</el-button><el-button type="info">重置</el-button></el-form-item></el-form></div></div>
</template>
<script>
export default {name: "Login",data() {return {//数据绑定loginForm: {username: '张三',password: '123456'},}},methods:{}
}
</script><style  scoped>
.login_container {background-color: #2b5b6b;height: 100%;
}
.login_box {width: 450px;height: 300px;background: #fff;border: 1px solid #42b983;border-radius: 3px;position: absolute;left: 50%;top: 50%;transform: translate(-50%, -50%);}
.login_box>.avatar_box {height: 130px;width: 130px;border: 1px solid #eee;border-radius: 50%;padding: 10px;box-shadow: 0 0 10px #ddd;position: absolute;left: 50%;transform: translate(-50%, -50%);background-color: #fff;}
.login_box>.avatar_box>img {width: 100%;height: 100%;border-radius: 50%;background-color: #eee;
}
.login_form {position: absolute;bottom: 0;width: 100%;padding: 0 20px;box-sizing: border-box;
}
.btns {display: flex;justify-content: flex-end;
}
</style>
  1. 在views中创建视图——登录页面

  2. 在router的index.js中配置路由

{path: '/',name: 'home',//重定向,使之打开页面就跳转到登录页面redirect: '/login',},//配置登录页面的路由{path: '/login',name:'login',component: () => import('../views/Login.vue'),},
  1. 在App.vue默认组件中进行路由渲染
<template><div id="app"><router-view/></div>
</template>

3. 登录按钮的点击事件

1. 首先,需要在main.js全局配置中全局配置axios

  1. 导入axios
  2. 设置axios的基础路径:端口号为后端项目的端口号
  3. 将axios挂载到vue对象中
import axios form 'axios'//导入
axios.dafaults.baseURL="基础路径http://ip:端口号" //配置axios的基础路径,便于在进行axios请求时将其省略
Vue.prototype.$名称=axios//将axios挂载到vue对象中。axios要与导入时的import后的名称一致。

2. 然后,在login页面的登录页面添加点击事件

  1. 在loginForm表单中添加表单验证——>:rules关键字和ref
  2. 在data中添加表单验证的规则
  3. 实现点击事件
  • 表单验证

    在这里插入图片描述

  • 验证规则

    在这里插入图片描述

  • 登录点击事件

    myLogin(){this.$refs.LoginFormRef.validate(valid => {if(valid){this.$axios.post('/login?username='+this.loginForm.username+'&password='+this.loginForm.password).then(res=>{if(res.data.code == 200){this.$message.success("登录成功")//将token保存到sessionStorage,类似于cookiesessionStorage.setItem("token",res.data.data)//跳转到后台this.$router.push("/home")}else{this.$message.error("登录失败")}})}})}
    

在该请求中,将获取到的token存放到sessionStorage中,通过setItem方法

解决跨域问题

此时允许点击“登录”按钮,会报错,出现跨域问题

在这里插入图片描述

跨域问题:通过ajax从一个服务访问另一个服务时,出现跨域问题

服务:只要ip或端口或协议不同,都称为不同的域

如何解决:

由两种方式:前端解决和后端解决,这里仅讲解后端的解决方式

  • 后端解决

    在config中创建一个用于解决跨域问题的配置类

    @Configuration
    public class AllowOriginConfig implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**") // 所有接口.allowCredentials(true) // 是否发送 Cookie.allowedOrigins("*")//支持域// .allowedOriginPatterns("*") // 支持域.allowedMethods(new String[]{"GET", "POST", "PUT", "DELETE"}) // 支持方法.allowedHeaders("*").exposedHeaders("*");}
    }
    

    在security配置类中添加登录允许跨域的设置

    因为其他需求可以,而login不行,因为login是security写的,不止自己写的

    http.cors();
    
     @Overrideprotected void configure(HttpSecurity http) throws Exception {//把自定义的过滤器放在之前http.addFilterBefore(loginFilter, UsernamePasswordAuthenticationFilter.class);http.formLogin()//登录页面;//登录的处理路径 默认 /login.loginProcessingUrl("/login").successHandler(successHandler())//登录成功.failureHandler(failureHandler()) //登录失败转发的路径 必须为post请求.permitAll(); //上面的请求路径无需认证//指定权限不足跳转的页面http.exceptionHandling().accessDeniedHandler(accessDeniedHandler());http.csrf().disable();//禁用跨域伪造请求的过滤器//security登录允许跨域http.cors();//除了上的请求,其他请求都需要认证http.authorizeRequests().anyRequest().authenticated();}
    

4. 前置路由守卫

前置路由守卫用于判断有没有登录

放在main.js或/router/index.js中

在设置前置路由守卫之前,在没有登录的情况下,可以直接访问登录后的页面——不符合现实,所以使用前置路由守卫,来判断有没有登录

  1. 先查看路径,若用户访问的是登录页面/login,直接放行
  2. 若不是,就获取sessionStorage中保存的token值
  3. 若token不存在,或者token为undefined,就强制跳转到/login登录页面
  4. 如果token存在,直接放行
//前置路由守卫
//to:即将要访问的路径
//from:从哪里来
//next:放行函数
router.beforeEach((to,from,next)=>{//如果用户访问的是登录页面,直接放行if(to.path === '/login'){//放行return next();}//获取sessionStorage中保存的token值const token = window.sessionStorage.getItem('token');//如果token不存在,强制跳转到登录页面if(!token){return next("/login");}//如果token存在,直接放行next();
})

5. 设置携带token令牌:请求拦截器

在未设置请求拦截器之前,成功登录后,点击按钮均显示“未登录”,是因为请求没有携带token令牌,后端判断为未登录

放在main.js中

//设置请求拦截器——携带token令牌
axios.interceptors.request.use(config=>{var token = sessionStorage.getItem("token");if(token){config.headers.token = token;}return config;
})

6. 设置响应拦截器

确保后端,返回类型为R类型

main.js中设置响应拦截器

  • 后端示例
@PreAuthorize("hasAuthority('user:query')")@GetMapping("/select")public R select(){System.out.println("查询用户");return new R(200,"查询用户","查询用户");}
  • 前端响应拦截器
//设置响应拦截器
axios.interceptors.response.use(response=>{//如果返回的code为200,为成功,显示返回的信息if(response.data.code===200){Vue.prototype.$message.success(response.data.msg);return response;}else {//否则,为失败,显示返回的信息Vue.prototype.$message.error(response.data.msg);return response;}
})

设置响应拦截器之后,就可以通过响应拦截器将后端的信息显示到前端页面,无需在axios请求中再次处理相关msg

  • 示例

    methods:{query(){this.$axios.get('/user/select').then(res=>{})},insert(){this.$axios.get('/user/add').then(res=>{})},del(){this.$axios.get('/user/delete').then(res=>{})},update(){this.$axios.get('/user/update').then(res=>{})},myExport(){this.$axios.get('/user/export').then(res=>{})}},

7. 退出

后端:借助redis完成。

  1. 在登录时,登录成功后,将token存入到redis中
  2. 在配置时,自定义实现退出接口,使其在退出登录后,删除redis中的缓存信息,并返回json数据,而不是页面
  3. 在登录过滤器中,验证token时加判断,判断redis中是否存在登录的token

因为要借助redis,所以需要导入redis,并在配置文件中进行配置,并且开启装有redis的虚拟机,开启redis服务

  • 引入依赖

     <!--引入redis依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>
  • 在配置文件中添加redis相关配置

    #Redis服务器连接端口
    spring.redis.port=6379
    #Redis服务器地址
    spring.redis.host=172.16.7.112
  • 在登录成功后将token添加到redis中

    //将token存入redis缓存中
    redisTemplate.opsForValue().set("login:"+token,"");

    @Autowiredprivate StringRedisTemplate redisTemplate;//登录成功需要返回的json数据private   AuthenticationSuccessHandler successHandler(){return new AuthenticationSuccessHandler() {@Overridepublic void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {//设置响应编码httpServletResponse.setContentType("application/json;charset=utf-8");//获取输出对象PrintWriter writer = httpServletResponse.getWriter();//返回json数据Map<String,Object> map=new HashMap<>();map.put("username",authentication.getName());//获取权限信息列表Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();//获取权限标识码List<String> collect = authorities.stream().map(item -> item.getAuthority()).collect(Collectors.toList());map.put("permission",collect);String token = JWTUtil.createToken(map);//将token存入redis缓存中redisTemplate.opsForValue().set("login:"+token,"");//返回一个统一的json对象R r=new R(200,"登录成功!",token);//转换未json字符串String s = JSON.toJSONString(r);//servlet//发送响应到客户端writer.println(s);//将JSON字符串写入到HTTP响应中writer.flush();//确保所有缓冲的输出都被发送到客户端writer.close();//关闭PrintWriter}};}
  • 在security配置文件中重写退出方法

    //退出登录后,删除redis中的缓存信息
    redisTemplate.delete("login:"+token);

     @Overrideprotected void configure(HttpSecurity http) throws Exception {//把自定义的过滤器放在之前http.addFilterBefore(loginFilter, UsernamePasswordAuthenticationFilter.class);http.formLogin()//登录页面;//登录的处理路径 默认 /login.loginProcessingUrl("/login").successHandler(successHandler())//登录成功.failureHandler(failureHandler()) //登录失败转发的路径 必须为post请求.permitAll(); //上面的请求路径无需认证//指定权限不足跳转的页面http.exceptionHandling().accessDeniedHandler(accessDeniedHandler());http.csrf().disable();//禁用跨域伪造请求的过滤器//退出,重写使其返回json数据,而不是网页http.logout(item->{item.logoutSuccessHandler((httpServletRequest, httpServletResponse, e) -> {httpServletResponse.setContentType("application/json;charset=utf-8");PrintWriter writer = httpServletResponse.getWriter();String token = httpServletRequest.getHeader("token");//退出登录后,删除redis中的缓存信息redisTemplate.delete("login:"+token);R r=new R(200,"退出成功",null);String jsonString =JSON.toJSONString(r);writer.println(jsonString);writer.flush();writer.close();});});//security登录允许跨域http.cors();//除了上的请求,其他请求都需要认证http.authorizeRequests().anyRequest().authenticated();}
  • 在登录过滤器中添加判断条件

    !redisTemplate.hasKey("login:"+token

      //3. 验证tokenif(!JWTUtil.verify(token)||!redisTemplate.hasKey("login:"+token)){PrintWriter writer = httpServletResponse.getWriter();//返回一个token失效的json数据R r=new R(500,"token失效!",null);String s = JSON.toJSONString(r);writer.write(s);writer.flush();writer.close();return;}
  • 前端,添加退出点击事件,退出后删除sessionStorage中的token信息,并跳转返回登录页面

     logout(){this.$axios.post("/logout").then(res=>{//移除sessionStorage中的tokensessionStorage.removeItem("token")//跳转到登录页面this.$router.push("/login")})}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/389040.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数值分析——分段低次插值

关键字&#xff1a;Matalb&#xff1b;曲线拟合&#xff1b;高次病态特性&#xff1b;分段低次插值 系列文章目录 数值分析——拉格朗日插值 数值分析——牛顿插值多项式 数值分析——埃尔米特&#xff08;Hermit&#xff09;插值 文章目录 系列文章目录前言一、理论推导1.高次…

跟张良均老师学大数据人工智能-批量集训营开班中

随着我国大数据和人工智能产业的飞速发展&#xff0c;未来社会对高素质科技人才的需求日益旺盛。为助力广大青少年提前掌握前沿技术&#xff0c;实现自我价值&#xff0c;泰迪智能科技多名优秀老师联合打造暑期大数据人工智能集训营&#xff0c;旨在培养具备创新精神和实战能力…

工厂客流人数管控系统,智能识别统计员工人数

在当今高度自动化和智能化的工业环境中&#xff0c;工厂客流人数管控系统正发挥着至关重要的作用。这一系统不仅能够智能识别并统计员工人数&#xff0c;还为工厂的运营管理带来了诸多优势。 一、系统介绍 工厂客流人数管控系统采用高精度视觉技术和深度学习算法&#xff0c;通…

CTFHUB-文件上传-双写绕过

开启题目 1.php内容&#xff1a; <?php eval($_POST[cmd]);?> 上传一句话木马 1.php&#xff0c;抓包&#xff0c;双写 php 然后放包&#xff0c;上传成功 蚁剑连接 在“/var/www/html/flag_484225427.php”找到了 flag

泛化的最近点迭代法(Generalized-ICP)

Generalized-ICP算法是由斯坦福大学的Aleksandr V. Segal、Dirk Haehnel和Sebastian Thrun提出的&#xff0c;于2009年在Robotics science and system会议上发表。 GICP是一种ICP算法的变体&#xff0c;其原理与ICP算法相同&#xff0c;之所以称为泛化的ICP算法是因为大多数ICP…

react-日期选择器封装

文件 import { useMemo, useState, useEffect } from "react" import dayjs, { Dayjs } from "dayjs" import "dayjs/locale/zh-cn" import "./App.css" dayjs.locale("zh-cn")function SimpleCalendar() {// 当前时间对象…

802.11 wireshark 抓包

80211 wireshark 抓包 前言配置 monitor软件配置wireshark 操作 前言 本人习惯使用 Omnipeek 抓包分析&#xff0c;所以 wireshark 的实验只讲到抓包完成。 Windows 环境采用 wireshark 抓包是比较麻烦的&#xff0c;因为支持在 Windows 环境中支持抓包的网卡并不多&#xff0…

Spring面试篇章——Spring基本概述

Spring 的基本概述 Spring学习的核心内容—一图胜千言 IOC&#xff1a;控制反转&#xff0c;可以管理 Java 对象AOP&#xff1a;切面编程JDBCTemplate&#xff1a;是Spring提供一套访问数据库的技术&#xff0c;应用性强&#xff0c;相对好理解声明式事务&#xff1a;基于IOC …

docker compse简介与安装

目录 1. Docker Compose 简介 2. Docker Compose 安装 2.1 在 Ubuntu 上安装 Docker Compose 2.1.1 通过 apt 安装 2.1.2 使用官方脚本安装最新版本 2.2 在 CentOS 上安装 Docker Compose 2.2.2 使用官方脚本安装最新版本 2.2.3 使用 pip 安装 2.3 在 openEuler 上安装…

Python面试宝典第25题:括号生成

题目 数字n代表生成括号的对数&#xff0c;请设计一个函数&#xff0c;用于能够生成所有可能的并且有效的括号组合。 备注&#xff1a;1 < n < 8。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;["((()))","(()())","(())()"…

【ArcGIS+CityEngine】自行制作Lod1城市大尺度白膜数据

数据准备 50多个城市建筑矢量数据 链接&#xff1a;https://pan.baidu.com/s/1FiwTfXDwQ6tMDRACAwUZwQ 提取码&#xff1a;DYSK 数据分析 数据属性Floor&#xff0c;为建筑物楼层信息&#xff0c;据此信息下面将在CityEngine软件生成Lod1白膜数据。 软件准备 CityEngi…

创建了Vue项目,需要导入什么插件以及怎么导入

如果你不知道怎么创建Vue项目,建议可以看一看这篇文章 怎么安装Vue的环境和搭建Vue的项目-CSDN博客 1.在idea中打开目标文件 2.系在一个插件Vue.js 3.下载ELement UI 在Terminal中输入 # 切换到项目根目录 cd vueadmin-vue # 或者直接在idea中执行下面命令 # 安装element-u…

[GYCTF2020]Blacklist1

打开题目 判断注入类型&#xff0c;输入1试试 输入2 输入1 判断为字符型注入 堆叠查询2;show databases;# 然后来输入2; show tables;#来查看数据库的表 然后我们通过FlagHere表来查看列输入2;show columns from FlagHere;# 来查看列 、 重新构造payload&#xff1a;0;HAND…

基于FPGA的高精度多通道同步AD采集系统开发及数字信号处理算法应用,基于FPGA的多通道同步AD采集系统开发及数字信号处理算法实现

FPGA多通道同步AD采集 AD7606 8通道16位高精度同步采集系统开发&#xff0c;采样率200KSPS&#xff0c;采集数据支持DDR3缓存、串口发送、USB2.0上传、千兆以太网上传等。 支持基于FPGA的数字信号处理算法开发 ID:77500703611886617 塞纳河山 FPGA多通道同步AD采集是一项基于…

官宣!新增博士硕士点审核结果已出!附查询方法

2024年7月31日&#xff0c;新增博士硕士学位授权结果正式公示&#xff01; 多所高校&#xff0c;新增博士和硕士学位授权点 大家可前往该网站查询&#xff1a;https://zjpy.cdgdc.edu.cn/sqshjggb 另外说明一下&#xff0c;这些学校不一定今年就开展招生工作 一切以学校的官…

9.Redis的Set类型

Redis的Set结构与java中的HashSet类似。 可以看做是一个value为null的HashMap。 特点 1.无序 2.元素不可重复 3.查找快 4.支持交集、并集、差集等功能 应用场景 实现共同关注&#xff0c;共同好友。 常见命令 sadd key 元素1 元素2 给set集合添加一个或多个元素 smem…

Kimi+AiPPT的正确打开方式!文档一键转换PPT!限时免费!

大家好,我是木易,一个持续关注AI领域的互联网技术产品经理,国内Top2本科,美国Top10 CS研究生,MBA。我坚信AI是普通人变强的“外挂”,专注于分享AI全维度知识,包括但不限于AI科普,AI工具测评,AI效率提升,AI行业洞察。关注我,AI之路不迷路,2024我们一起变强。 我之前…

做管理,一定要避开这6个坑,才能成就优秀管理者

做管理&#xff0c;一定要避开这6个坑&#xff0c;才能成就优秀管理者 一、被平庸的员工绑架 要是领导不敢或者不愿意惩罚或者开除那些没完成任务的员工&#xff0c;那优秀的员工就会觉得&#xff0c;做得好做得差都一样&#xff0c;那谁还愿意努力呢&#xff1f; 二、总想改变…

基于双PI控制器结构的六步逆变器供电无刷直流电机调速simulink仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 4.1 无刷直流电机&#xff08;BLDCM&#xff09;原理 4.2 六步换相逆变器 4.3 双PI控制器设计 5.完整工程文件 1.课题概述 基于双PI控制器结构的六步逆变器供电无刷直流电机调速simulink仿真。双PI控制…

DockerCompose部署示例

目录 前言 1. 初识DockerCompose 2. 安装DockerCompose 3. 部署微服务项目 1&#xff09;找一个目录&#xff0c;创建一个新的cloud-demo文件夹。 2&#xff09;在cloud-demo文件夹创建一个docker-compose.yml文件&#xff0c;然后编写下面内容&#xff1a; 3&#xff09…