Javaweb-day12(登录认证)

登录功能

登录校验(重点)

登录校验指的是在服务器接收到浏览器发送过来的请求之后,首先要对这个请求进行校验,先要校验一下用户登录了没有

怎么来实现登录校验的操作呢?具体的实现思路可以分为两部分:

  1. 在员工登录成功后,需要将用户登录成功的信息存起来,记录用户已经登录成功的标记。

  2. 在浏览器发起请求时,需要在服务端进行统一拦截,拦截后进行登录校验。

会话技术

会话跟踪技术:

Cookie(客户端会话跟踪技术)

数据存储在客户端浏览器当中

服务器端在给客户端在响应数据的时候,会自动 的将 cookie 响应给浏览器,浏览器接收到响应回来的 cookie 之后,会自动 的将 cookie 的值存储在浏览器本地。接下来在后续的每一次请求当中,都会将浏览器本地所存储的 cookie 自动地携带到服务端。

Session(服务端会话跟踪技术)

数据存储在储在服务端

底层就是基于cookie实现的

令牌技术

令牌就是一个用户身份的标识,本质就是一个字符串

如果通过令牌技术来跟踪会话,我们就可以在浏览器发起请求。在请求登录接口的时候,如果登录成功,我就可以生成一个令牌,令牌就是用户的合法身份凭证。接下来我在响应数据的时候,我就可以直接将令牌响应给前端。

接下来我们在前端程序当中接收到令牌之后,就需要将这个令牌存储起来。这个存储可以存储在 cookie 当中,也可以存储在其他的存储空间(比如:localStorage)当中。

接下来,在后续的每一次请求当中,都需要将令牌携带到服务端。携带到服务端之后,接下来我们就需要来校验令牌的有效性。如果令牌是有效的,就说明用户已经执行了登录操作,如果令牌是无效的,就说明用户之前并未执行登录操作。

此时,如果是在同一次会话的多次请求之间,我们想共享数据,我们就可以将共享的数据存储在令牌当中就可以了。

JWT令牌

简洁:是指jwt就是一个简单的字符串。可以在请求参数或者是请求头当中直接传递。

自包含:指的是jwt令牌,看似是一个随机的字符串,但是我们是可以根据自身的需求在jwt令牌中存储自定义的数据内容。如:可以直接在jwt令牌中存储用户的相关信息。

简单来讲,jwt就是将原始的json数据格式进行了安全的封装,这样就可以直接基于jwt在通信双方安全的进行信息传输了。

java 复制代码
//   生成JWT 
    @Test
    public void testGenJwt(){
        Map<String,Object> claims = new HashMap<>();
        claims.put("id",1);
        claims.put("name","tom");

        String jwt = Jwts.builder()
                .signWith(SignatureAlgorithm.HS256,"wujiaowujiao")//签名算法
                .setClaims(claims)//自定义内容(载荷)
                .setExpiration(new Date(System.currentTimeMillis()+3600*1000))//设置有效期为1h
                .compact();
        System.out.println(jwt);
    }
//    解析JWT
    @Test
    public void testParseJWT(){
        Claims claims = Jwts.parser()
                .setSigningKey("wujiaowujiao")//指定签名密钥
                .parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoidG9tIiwiaWQiOjEsImV4cCI6MTczMTc0MDk2MH0.XNxy4S4R9U_PyYf17xNeHLHIaFIFmB3fSQW7xwCm2SM")//解析令牌
                .getBody();
        System.out.println(claims);
    }

过滤器Filter

快速入门

filter是Javaweb三大组件之一,并不是springboot当中提供的功能,在springboot项目中,要想使用javaweb的三大组件,必须在启动类上面加上一个注解@ServletComponentScan

详解
执行流程

过滤器拦截到了请求之后,首先先执行放行之前的逻辑,放行之前的逻辑执行完毕之后,执行放行操作,放行就是调用 FilterChain对象当中的doFilter()方法,在调用doFilter()这个方法之前所编写的代码属于放行之前的逻辑。

在放行后访问完 web 资源之后还会回到过滤器当中,回到过滤器之后如有需求还可以执行放行之后的逻辑,放行之后的逻辑我们写在doFilter()这行代码之后。

拦截路径
过滤器链

过滤器链指的是在一个web应用程序当中,可以配置多个过滤器,多个过滤器就形成了一个过滤器链。

通过控制台日志的输出,大家发现AbcFilter先执行DemoFilter后执行,这是为什么呢?

其实是和过滤器的类名有关系。以注解方式配置的Filter过滤器,它的执行优先级是按时过滤器类名的自动排序确定的,类名排名越靠前,优先级越高。

登录校验-Filter

因为tomcat传入的request实际上是HTTPrequest 这里是多态的思想

看一下源码就可以了,这里传递的是父类接口,这样子接口就可以完美兼容父接口

不懂不懂为什么

在tomcat那一章节,tomcat会将解析后的请求信息封装到一个对象中,这个对象就是httpservletrequest,我有这个印象

测试这块没跟,之后可以再看一下。

拦截器Interceptor

简介&快速入门

在拦截器当中,我们通常也是做一些通用性的操作,比如:我们可以通过拦截器来拦截前端发起的请求,将登录校验的逻辑全部编写在拦截器当中。在校验的过程当中,如发现用户登录了(携带JWT令牌且是合法令牌),就可以直接放行,去访问spring当中的资源。如果校验时发现并没有登录或是非法令牌,就可以直接给前端响应未登录的错误信息。

下面我们通过快速入门程序,来学习下拦截器的基本使用。拦截器的使用步骤和过滤器类似,也分为两步:

  1. 定义拦截器

  2. 注册配置拦截器

详解
拦截路径
执行流程

tomcat服务器不识别所编写的control程序,但是它识别servlet程序,因为tomcat是一个servlet容器,在springweb环境中,提供了一个非常核心的servlet,叫做前端控制器(DispatcherServlet)

  • 当我们打开浏览器来访问部署在web服务器当中的web应用时,此时我们所定义的过滤器会拦截到这次请求。拦截到这次请求之后,它会先执行放行前的逻辑,然后再执行放行操作。而由于我们当前是基于springboot开发的,所以放行之后是进入到了spring的环境当中,也就是要来访问我们所定义的controller当中的接口方法。

  • Tomcat并不识别所编写的Controller程序,但是它识别Servlet程序,所以在Spring的Web环境中提供了一个非常核心的Servlet:DispatcherServlet(前端控制器),所有请求都会先进行到DispatcherServlet,再将请求转给Controller。

  • 当我们定义了拦截器后,会在执行Controller的方法之前,请求被拦截器拦截住。执行preHandle()方法,这个方法执行完成后需要返回一个布尔类型的值,如果返回true,就表示放行本次操作,才会继续访问controller中的方法;如果返回false,则不会放行(controller中的方法也不会执行)。

  • 在controller当中的方法执行完毕之后,再回过来执行postHandle()这个方法以及afterCompletion() 方法,然后再返回给DispatcherServlet,最终再来执行过滤器当中放行后的这一部分逻辑的逻辑。执行完毕之后,最终给浏览器响应数据。

登录校验

登录校验的过滤器和拦截器,我们只需要使用其中的一种就可以了。

这次测试跟了。

java 复制代码
package com.wujiao.interceptor;

import com.alibaba.fastjson.JSONObject;
import com.wujiao.pojo.Result;
import com.wujiao.utils.JwtUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

@Component
@Slf4j
public class LoginCheckInterceptor implements HandlerInterceptor {

    @Override//目标资源方法运行前运行,即controller方法,返回true;放行,返回false,不放行
    public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) throws Exception {
        System.out.println("preHandle...");

//        1. 获取请求url
        String url = req.getRequestURL().toString();
        log.info("请求的url:{}",url);
//        2. 判断请求url中是否包含login,如果包含,说明是登录操作,放行
        if(url.contains("login")){
            log.info("登录操作,放行...");
            return true;
        }
//        3. 获取请求头中的令牌(token)
        String jwt = req.getHeader("token");
        log.info("从请求头中获取的令牌:{}",jwt);

//        4. 判断令牌是否存在,如果不存在,返回错误结果(未登录)
        if(!StringUtils.hasLength(jwt)){
            log.info("请求头token为空,返回未登录的信息");
            Result error = Result.error("NOT_LOGIN");
            String notLogin = JSONObject.toJSONString(error);//把Result对象转换为JSON格式字符串 (fastjson是阿里巴巴提供的用于实现对象和json的转换工具类)
            res.getWriter().write(notLogin);
            return false;

        }
//        5. 解析token,如果解析失败,返回错误结果(未登录)
        try {
            JwtUtils.parseJWT(jwt);
        } catch (Exception e) {//jwt解析失败

            log.info("解析令牌失败,返回未登录错误信息");
            Result error = Result.error("NOT_LOGIN");
            String notLogin = JSONObject.toJSONString(error);//把Result对象转换为JSON格式字符串 (fastjson是阿里巴巴提供的用于实现对象和json的转换工具类)
            res.getWriter().write(notLogin);
            return false;
        }
//        6. 放行
        log.info("令牌合法,放行");
        return true;
    }

    @Override//目标资源方法运行后运行
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle...");
    }

    @Override//视图渲染完毕后运行,最后运行
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion...");
    }
}

异常处理

程序开发过程中不可避免的会遇到异常现象

出现异常时,默认返回的结果不符合规范,即返回的不是json格式的数据

以上就是全局异常处理器的使用,主要涉及到两个注解:

  • @RestControllerAdvice //表示当前类为全局异常处理器

  • @ExceptionHandler //指定可以捕获哪种类型的异常进行处理

java 复制代码
package com.wujiao.exception;

import com.wujiao.pojo.Result;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

//全局异常处理器
@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(Exception.class)//捕获所有异常
    public Result ex(Exception ex){
        ex.printStackTrace();
        return Result.error("对不起,操作失败,请联系管理员");
    }

}

及时复习呀

相关推荐
studyForMokey3 分钟前
[Kotlin标准函数] run、with、apply、also、let、use等
前端·python·kotlin
hhhalloWelt20 分钟前
头歌-本关任务:使用GmSSL命令行,生成SM2私钥并对文件进行签名验证(第二关)。
linux·运维·服务器
随·枫37 分钟前
datalist 是什么?以及作用是什么?
前端
码农小丘1 小时前
第二章 Spring Boot快速⼊⻔ —— Spring Boot配置文件
java·前端·spring boot
vortex51 小时前
Linux 下敏感文件路径总结
linux·运维·服务器
阿拉伯梳子1 小时前
无线网络信号 6G、5G和2.4G 的一些小科普
运维·服务器
yqcoder1 小时前
reactflow 中 selectionMode 组件作用
前端·javascript
伏飞而行1 小时前
七、利用CSS和多媒体美化页面的习题
前端·css·html5
爱上口袋的天空2 小时前
04 - Clickhouse-21.7.3.14-2单机版安装
linux·服务器·clickhouse
AAA 建材批发王哥(天道酬勤)2 小时前
在 Unix 和类 Unix 操作系统中,信号是一种异步的通知机制,用于通知进程发生了一些特定的事件。
服务器·unix