将仅完成登录匹配的登陆系统进行完善

本文介绍了完善登录过程的细节,包括在登录成功后生成JWTToken并存储在前端,使用路由导航守卫判断用户登录状态,以及后端如何通过Token进行会话跟踪和验证。同时,讨论了如何通过Axios拦截器自动添加Token到请求头,确保每次交互的安全性。
摘要由CSDN通过智能技术生成

引入

上节课学习了Ajax,Axios,跨域,Json等东西,学会了,前端页面的登录,但是页面还不完善,且用户登录界面只需通过URL便可以登录,无需登录,这显然不合理,我们这节课来解决一下

1. 显示账号

登录成功后,在前端保存用户信息,并且在main界面中显示用户账号

sessionStorage.setItem("username",resp.data.data.account);会话级别,浏览器关闭即清除
localStorage.setItem("key","value");//长久保存,除非手动清除

这里通过利用浏览器本地的一个会话级别的存储空间,它有一个特点,存储数据,浏览器关闭时自动删除,但是这里仍有缺陷,前端数据并不可靠,用户可能在浏览器的存储空间中篡改数据。

2. 判断登录

来到main组件时,需要在前端判断用户是否登录,并且在后台管理中的许多组件中都需要判断用户是否已经登录,自己判断非常麻烦,在路由中提出了一个叫路由导航守卫的功能,每次发生组件路由时,都会触发一个方法,通过将以下代码配置到index.js中解决

rout.beforeEach((to,from,next)=>{
	if(to.path=='/login'){//如果用户访问的登录页,直接放行
		return next();
	}else{
		//这里获取本地会话空间中的usrname判断值是否为空,空则登录
    	var token = sessionStorage.getItem("username");
    	if(token==null){
       		return next("/login");
    	}else{
       		next();
    	}
	}
})

3. web会话跟踪技术

在web前端与后端的交互过程中,后端如何知道是哪个用户在此进行操作?为什么后端不知道是哪个用户请求的?

答:因为http请求是无状态的(请求–响应的模式),请求中没有能识别对方身份的标识,可以认为每次请求是独立的。

那么我们在实际开发中就需要解决这个问题,每次向后端发送请求时,需要让后端知道是哪个用户发送的,这个实现的功能称为web会话跟踪技术。

在现在的会话跟踪中, 基于token的会话跟踪技术 在之前还有一种基于HttpSession的会话技术

目标

1.是在登录成功后,在后端生成一个token(令牌)的字符串(可以携带用户信息,加密),

JWT–>json web token是生成token的一种方式

jwt生成token,这种方法优点:

  1. 简洁
  2. 可以携带用户信息
  3. 可以加密
  4. 不需要在服务器端存储,节省空间

token中信息包含几个部分

  1. 第一段字符串由base64(可逆)加密算法得到
  2. 第二段由payload信息通过base64加密算法得到,一般放不敏感信息
  3. 将第一段和第二段密文拼接起来,对拼接起来的密文和自定义的盐处理,对加密后的密文在做base64加密

如何生成

  1. 导入jwt组件的jar
  2. 导入JwtUtil类 包含生成token,验证token,解析token中用户信息部分

2.将此字符串响应到浏览器(前端),并存储起来

sessionStorage.setItem("token",resp.data.data.token);

这里Token就解决了前端篡改数据的问题,如果你的存储空间数据违法,后端会抛出异常,不会认可,篡改也就毫无意义。

3.然后将此token每次与后端交互时,都放在请求头中,

这时一个测试方法,执行一次便向后端发送一次token

test(){//token已经添加在请求头中
    var token = sessionStorage.getItem("token");
    this.$http.get("login?token="+token).then((resp)=>{

    })
}

我们需要每发送一次请求就发送一次token的方法,而这个方法还需要每次调用十分麻烦

上有政策,下有对策,这里有一个Axios拦截器,每向后端发送一次请求,都会在请求头携带一个token中

//Axios请求拦截
axios.interceptors.request.use(config =>{
//为请求头添加一个自定义请求头,只需定义一次即可
config.headers.token = window.sessionStorage.getItem('token');
return config;
})

4.后端接收到token后,会对token进行验证,是否符合规则,符合继续执行,不符合直接响应验证失败

这里后端接收到Get请求头中的Token并对其进行验证,这时LoginServlet中的代码

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setHeader("Content-Type", "text/html;charset=utf-8");//设置响应内容的编码
        PrintWriter pt = resp.getWriter();
        //获取前端传送过来的token
        String token = req.getHeader("token");
        System.out.println(token);
        //验证token
        boolean res = JWTUtil.verify(token);
        CommonResult commonResult = new CommonResult(res?200:202,res,"验证token");
        ObjectMapper objectMapper = new ObjectMapper();
        String json = objectMapper.writeValueAsString(commonResult);
        pt.print(json);
    }

我们每次在接收到token时都要进行验证,这里我们将验证写进过滤器

package com.ffyc.webback.filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.ffyc.webback.util.CommonResult;
import com.ffyc.webback.util.JWTUtil;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class TokenFilter implements Filter {


    @Override//HttpServletRequest extends ServletRequest
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest)servletRequest;
        String token = req.getHeader("token");
        boolean res = JWTUtil.verify(token);
        if(res){//token验证正确,继续执行下一个过滤器或Servlet
            filterChain.doFilter(servletRequest,servletResponse);
        }else{//token 验证失败,无需向下走了
            HttpServletResponse resp = (HttpServletResponse) servletResponse;
            resp.setHeader("Content-Type", "text/html;charset=utf-8");//设置响应内容的编码
            PrintWriter pt = resp.getWriter();
            CommonResult commonResult = new CommonResult(202,res,"验证token失败");
            ObjectMapper objectMapper = new ObjectMapper();
            String json = objectMapper.writeValueAsString(commonResult);
            pt.print(json);
        }
    }
}

这里我们前端测试的get请求发送到TestServlet中,同时将LoginSerlvet中的doget方法删除并复制到TestServlet中

package com.ffyc.webback.servlet;

import com.auth0.jwt.interfaces.DecodedJWT;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ffyc.webback.util.CommonResult;
import com.ffyc.webback.util.JWTUtil;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class TestServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setHeader("Content-Type", "text/html;charset=utf-8");//设置响应内容的编码
        PrintWriter pt = resp.getWriter();
        //获取前端传送过来的token
        String token = req.getHeader("token");
        DecodedJWT decodedJWT = JWTUtil.getTokenInfo(token);
        Integer id = decodedJWT.getClaim("id").asInt();
        String username = decodedJWT.getClaim("username").asString();
        System.out.println("测试请求"+id+":"+username);
        //验证token
        boolean res = JWTUtil.verify(token);
        CommonResult commonResult = new CommonResult(200,res,"测试成功");
        ObjectMapper objectMapper = new ObjectMapper();
        String json = objectMapper.writeValueAsString(commonResult);
        pt.print(json);
    }
}

一个关于配置的小问题,也是基于目前情况,这里测试向TestServlet发送请求,所以我们不需要向LoginServelt,那我们如何配置web.xml呢,是直接在url-pattern中填入/test吗,如果处理LoginServlet以外的Servelt都要添加TokenFilter过滤器,那这个时候配置就变得十分苦难,我们在TestServlet中改XML为

    <!--注册项目中的servlet-->
    <servlet>
        <servlet-name>testServlet</servlet-name>
        <servlet-class>com.ffyc.webback.servlet.TestServlet</servlet-class>
    </servlet>
    <!--为servlet配置访问地址-->
    <servlet-mapping>
        <servlet-name>testServlet</servlet-name>
        <url-pattern>/admin/test</url-pattern>
    </servlet-mapping>

而LoginServletxml设置不变同时重新设置TokenFilter中的配置为

    <filter>
        <filter-name>tokenFilter</filter-name>
        <filter-class>com.ffyc.webback.filter.TokenFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>tokenFilter</filter-name>
        <url-pattern>/admin/*</url-pattern>
    </filter-mapping>

以上设置/admin/*为为admin访问路径下的所有子路径添加tokenFilter过滤器,在所有要加该过滤器的位置配置url-pattern为/admin/xxx

这时前端接受请求后,code=202即为token验证失败,退出用户系统,代码为

test(){//token已经添加在请求头中
				this.$http.get("admin/test").then((resp)=>{
					if(resp.data.code==202){
						this.$message({message:resp.data.message,type:'warning'});
						this.$router.push("/login");
					}
				})
			}

那么退出的方法也需要改变了,因为退出本地会话空间中的username,当再次通过URL访问用户系统时,本地会话空间的username不为空,直接跳入用户界面,我们在日常操作中退出之后,再次进入理当重新输入密码,所以,退出方法也需要修改,这时修改后的方法,退出之后,清除本地的用户信息

out(){
    this.$confirm('确定要退出吗?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
    }).then(() => {
        sessionStorage.clear();//清空本地会话空间
        this.$router.push("/login");
    });
},

4. 梳理

本节课优化了登录操作,在前面我们写的登录界面就只能判断用户的数据,而这节课我们

  1. 先将用户名显示到了用户系统上
  2. 判断用户是否登录,当每次访问新网页,如果本地会话空间中的username为空,我们认为用户其实已近推出过浏览器,则让其进入登录界面,使用的路由导航守卫,这样每次切换访问页面时都会进行判断,无需重复代码
  3. 因为Http无状态,每次请求都只会返回访问的数据,而不像TCP那样基于连接,因此知道本次用户是谁,在这里我们引入了token(令牌),这种token可以存储用户信息,加密,不需要存储在服务器,十分方便。在第一次用户请求发送到后端时,在后端根据加密方式生成了一个和用户信息有关的token字符串,然后将token通过过滤器每次存储在响应头中并发送给用户,浏览器接收到token之后便存储在了本地会话空间,以后每次访问后端时都要发送这个token,如果token正确,执行相应操作,token错误,则用户进行了信息的篡改,立即退出用户系统,进入登陆界面。上几次我们还写过一个退出方法,当时写方法时退出没有清理本地会话空间中的username,所以推出之后,用户可以通过URL再次访问,这显然不合理,我们在每次登录之后清楚本地会话空间中的数据即可
  4. 这样一个基本的登录就完成了
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值