当前位置: 首页 > article >正文

JavaEE Servlet03

目录

浏览器保存用户信息

路由导航守卫

路由嵌套

web会话跟踪机制

JWT生成token(json wen token)

起源

传统的session认证

基于session认证所暴露的问题

基于token的鉴权机制

JWT的主要应用场景

优点:

JWT的构成

第一部分:头部(header)

base64

第二部分:载荷(payload,用户的信息)

第三部分:签证(signature)

JWT搭建

引入JWT依赖,由于是基于java,所以需要的是java-jwt

创建生成token的方法

JWT组件

验证token是否有效

axios请求拦截

token过滤器

响应拦截器

获得token中playload部分数据 


浏览器保存用户信息

会话期间存储,关闭浏览器后数据就会销毁
sessionStorage.setItem();

//在前端浏览器中存储用户信息
//会话期间存储,关闭浏览器后数据就会销毁
sessionStorage.setItem("account",resp.data.result.account);
sessionStorage.setItem("gender",resp.data.result.gender);
sessionStorage.setItem("phone",resp.data.result.phone);

效果

localStorage.setItem("","");
本地存储,即使关闭浏览器,下次打开还是存在,可以长久保存  

路由导航守卫

目前除了访问呢login.vue是不需要登录,除此之外的组件,都必须要登录后才能访问

使用vue-router中的路由导航守卫,在前端每次发生路由跳转时会触发拦截

判断访问哪些组件,哪些组件需要登录,哪些组件不需要登录

路由导航守卫,前端每发生一次路由跳转时,会自动触发beforeEach().

rout.beforeEach((to,from,next)=>{
    if(to.path=='/login'){//如果访问登录组件,不需要做任何判断,直接放行到目标组件去
        return next();//放行到目标文件
    }else{
        var token = window.sessionStorage.getItem("account");
        if(token==null){//用户信息为空,说明用户没有登录
            return next("/login");
        }else{//说明用户已经登录
            next();
        }
    }
})

目前只是在前端做了控制,后端同样需要进行控制

路由嵌套

在main路由下嵌套其他子路由

<template slot="title"><i class="el-icon-message"></i>操作菜单</template>
<el-menu-item-group> 
<el-menu-item index="/majorlist">专业管理</el-menu-item>
<!--路由地址-->
<el-menu-item index="/studentlist">学生管理</el-menu-item>
</el-menu-item-group> 

index.js导入组件

import MajorList from "../views/major/MajorList.vue";
import StudentList from "../views/student/StudentList.vue";

在el菜单上加一个router,这样我们的菜单是路由的

<el-menu :default-openeds="['1', '3']" router>

将major和student路由嵌套到main下

        {
            path: '/main',
            component: Main,
			children:[
				{
					path: "/majorlist",
		            component: MajorList
				},
				{
					path: "/studentlist",
		            component: StudentList
				}				
			]
        }

mian.vue

<el-main>
    <router-view></router-view>
</el-main>

web会话跟踪机制

因为http请求是无状态的,一次强求响应结束后,就结束了

下一次再向服务器端发送请求,服务器并不知道是谁向它发送的

我们需要对整个会话过程进行跟踪:

1、当登录时,后端验证密码是否正确,如果账号正确,就需要在后端为当前登录的用户生成一个令牌(token)将令牌信息响应给前端

2、前端存储token

3、后面每一次从前端向后端发送请求都要携带token

4、后端验证令牌,如果令牌有效,继续向后执行,如果令牌无效,向前端响应失败,重新登录

JWT生成token(json wen token)

基于json的开放标准定义的一种简洁的,自包含的方法,用于通信双方以json对象的形式安全的传递信息。JWT可以使用HMAC算法或者是RSA是公私秘匙进行签名。

id-->token 秘匙-签名 

JWT就是用来生成token的方式,是一种可以携带用户信息,并且可以设置秘钥加密的字符串,是安全的。

起源

谈一谈基于token的认证和传统的session认证的区别

传统的session认证

将用户信息存储在服务器端,不好的地方:

1、占用服务器内存

2、分布式项目中,不灵活

基于session认证所暴露的问题

ssion: 每个用户经过我们的应用认证之后,我们的应用都要在服务端做一次记录,以方便用户下次请求的鉴别,通常而言session都是保存在内存中,而随着认证用户的增多,服务端的开销会明显增大

扩展性: 用户认证之后,服务端做认证记录,如果认证的记录被保存在内存中的话,这意味着用户下次请求还必须要请求在这台服务器上,这样才能拿到授权的资源,这样在分布式的应用上,相应的限制了负载均衡器的能力。这也意味着限制了应用的扩展能力。

CSRF (跨站请求伪造):因为是基于cookie来进行用户识别的, cookie如果被截获,用户就会很容易受到跨站请求伪造的攻击。

基于token的鉴权机制

基于token的鉴权机制类似于http协议也是无状态的,它不需要在服务端去保留用户的认证信息或者会话信息。这就意味着基于token认证机制的应用不需要去考虑用户在哪一台服务器登录了,这就为应用的扩展提供了便利。

流程上是这样的:

1. 用户使用账号和密码发出post请求;
2. 服务器使用私钥创建一个jwt;
3. 服务器返回这个jwt给浏览器;
4. 浏览器将该jwt串在请求头中像服务器发送请求;
5. 服务器验证该jwt;
6. 返回响应的资源给浏览器。

JWT的主要应用场景

可以用来验证用户身份以及对路由,服务和资源的访问权限进行验证。

由于信息是经过签名的,可以确保发送者发送的信息是没有经过伪造的。

优点:

1.简洁(Compact): 可以通过URLPOST参数或者在HTTP header发送,因为数据量小,传输速度也很快
2.自包含(Self-contained):负载中包含了所有用户所需要的信息,避免了多次查询数据库
3.因为Token是以JSON加密的形式保存在客户端的,所以JWT是跨语言的,原则上任何web形式都支持。
4.不需要在服务端保存会话信息,特别适用于分布式微服务。

JWT的构成

由三段信息构成,将三段信息文本用链接一起就构成了jwt字符串:

v51vdsvv45KJVHJUSVYD5VK.q3yqfy5q4qebshwny64w6q43t34y54qrtmanr3OH.AKCTW64XBVCSTXIcsDSbwhbvvonwqncpoi7h9p4

第一部分:头部(header)

jwt的头部承载两部分信息:

1、声明类型,这里是jwt

2、声明加密的方法:通常直接使用HMAC HS256

      完整的头部就像下面这样的JSON:

      {'typ':'JWT';'alg':'HS256'}-->重新进行编码

然后将头部进行base64转码,构成第一部分

v51vdsvv45KJVHJUSVYD5VK.

base64

链接:base64-CSDN博客

第二部分:载荷(payload,用户的信息)

存放有效信息的地方,形象理解为飞机上承载的货品,这些有效信息包含三个部分

1、标准中注册的声明

2、公共的声明

可以添加任何的信息。一般添加用户的相关信息或其他业务需要的必要信息/但不建议添加敏感信息(例如密码),因为该部分在客户端可解密。id,用户名,头像名  

3、私有的声明

      定义一个playload

      {"sub":"1234567890","name":"thesky","admin":true}

然后将头部进行base64转码,得到JWT第二部分

q3yqfy5q4qebshwny64w6q43t34y54qrtmanr3OH.

第三部分:签证(signature)

由三部分组成:

      header(base64后的)

      playload(base64后的)

      secret

需要base64转码后的header和base64转码后的playload使用连接组成新的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,构成jwt的第三部分

AKCTW64XBVCSTXIcsDSbwhbvvonwqncpoi7h9p4

JWT搭建

引入JWT依赖,由于是基于java,所以需要的是java-jwt

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

创建生成token的方法

JWT组件
package com.ffyc.dormserver.util;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.example.back.bean.User;
import com.ffyc.dormserver.model.Admin;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * JWT工具类
 */
public class JWTUtil {

    /**
     * 根据用户id,账号生成token
     * @param u
     * @return
     */
    public static String getToken(Admin admin) {
        String token = "";
        try {
            //过期时间 为1970.1.1 0:0:0 至 过期时间  当前的毫秒值 + 有效时间
            Date expireDate = new Date(new Date().getTime() + 10*1000);
            //秘钥及加密算法
            Algorithm algorithm = Algorithm.HMAC256("ZCEQIUBFKSJBFJH2020BQWE");
            //设置头部信息
            Map<String,Object> header = new HashMap<>();
            header.put("typ","JWT");
            header.put("alg","HS256");
            //携带id,账号信息,生成签名
            token = JWT.create()
                    .withHeader(header)
                    .withClaim("id",admin.getId())//第二部分
                    .withClaim("account",admin.getAccount())//第二部分
                    .withExpiresAt(expireDate)//第二部分
                    .sign(algorithm);//第三部分  秘钥  加盐
        }catch (Exception e){
            e.printStackTrace();
            return  null;
        }
        return token;
    }
}

后端获取token,将token响应给前端

            if(admin!=null){
                //登录成功后,为当前登录的用户生成token
                String token = JWTUtil.getToken(admin);
                admin.setToken(token);
                result = new Result<>(200,"登录成功",admin);
            }else{
                result = new Result<>(201,"账号或密码错误",null);
            }
sessionStorage.setItem("token",resp.data.result.token);

验证token是否有效

JWT组件

    /**
     * 验证token是否有效
     * @param token
     * @return
     */
    public static boolean verify(String token){
        try {
            //验签
            Algorithm algorithm = Algorithm.HMAC256("ZCEQIUBFKSJBFJH2020BQWE");
            JWTVerifier verifier = JWT.require(algorithm).build();
            DecodedJWT jwt = verifier.verify(token);
            return true;
        } catch (Exception e) {//当传过来的token如果有问题,抛出异常
            return false;
        }
    }
axios请求拦截
//axios 请求拦截,每当我们使用axios框架向后端发送请求时,都会经过拦截器
axios.interceptors.request.use(config =>{
	//为请求头对象,添加 Token 验证的 token 字段
	config.headers.token = sessionStorage.getItem('token');
	return config;
})
token过滤器
package com.ffyc.dormserver.filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.ffyc.dormserver.model.Result;
import com.ffyc.dormserver.util.JWTUtil;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/*
  验证token是否有效
*/
@WebFilter(urlPatterns = "/api/*")
public class TokenFilter implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //向下转型
        HttpServletRequest request = (HttpServletRequest)servletRequest;
        //从请求头中拿到token
        String token = request.getHeader("token");
        System.out.println("token验证过滤器");
        //验证token
        boolean verify = JWTUtil.verify(token);
        if(verify){
            //token验证成功继续向后执行,到达目标servlet程序
            filterChain.doFilter(servletRequest, servletResponse);
        }else{
            //token验证失败向前端响应401
            Result result = new Result(401,"token认证失败",null);
            servletResponse.getWriter().print(new ObjectMapper().writeValueAsString(result));
        }
    }
}
响应拦截器
// 添加响应拦截器
axios.interceptors.response.use((resp) =>{//正常响应拦截
    if(resp.data.code==500){
        ElementUI.Message({message:resp.data.desc,type:"error"})
    }
    if(resp.data.code==401){
	    ElementUI.Message({message:resp.data.desc,type:"error"})
        router.replace("/login");
    }
    return resp;
});
获得token中playload部分数据 
    /**
     * 获得token 中playload部分数据,按需使用
     * @param token
     * @return
     */
    public static DecodedJWT getTokenInfo(String token){
        return JWT.require(Algorithm.HMAC256("ZCEQIUBFKSJBFJH2020BQWE")).build().verify(token);
    }

http://www.kler.cn/a/585078.html

相关文章:

  • 虚拟化数据恢复—重装系统服务器崩了的数据恢复过程
  • 如何在 PostgreSQL 中运行 TLS 回归测试
  • 《C#上位机开发从门外到门内》2-5:USB通信
  • unity几种设计模式(自用)
  • 手写一些常见算法
  • 详解分辨率、像素值与图像大小:数字图像的三大支柱
  • cocos creator使用mesh修改图片为圆形,减少使用mask,j减少drawcall,优化性能
  • 框架_C语言_数据包解析代码框架
  • 08 | 实现版本号打印功能
  • 《C#上位机开发从门外到门内》2-6:CAN总线通信
  • DAY33 贪心算法Ⅱ
  • 系统架构的评估的系统的质量属性
  • Java学习--Redis
  • 【机器人-基础知识】欧拉角、旋转矩阵和四元数
  • SQL日期处理
  • 如何在PHP中实现OAuth2认证:安全性与可扩展性
  • 【实战ES】实战 Elasticsearch:快速上手与深度实践-6.2.2GDPR数据脱敏处理
  • Visual stdio2022 opencv cude pytroch与yolov8/可视化工具的环境搭建,不搞VIP,我也要当雷锋
  • TDE透明加密:免改造实现SQLServer数据库安全存储
  • Spring Boot集成Mybatis中如何显示日志