JavaWeb阶段学习知识点(二)

登录校验和JWT令牌实现

JWT使用方式

创建一个springboot项目,pom.xml引入jwt依赖

        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>

       <!-- 针对jdk17
			或者报错内容为:java.lang.NoClassDefFoundError: javax/xml/bind/DatatypeConverter 的
			小伙伴加一下下面的依赖 -->
	   <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.1</version>
        </dependency>

在测试类中,定义一个测试方法,测试jwt令牌生成

package com.jwz;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class test {
   

    /**
     * 生成jwt
     */
    @Test
    void testSetJwt() {
   
        Map<String, Object> claims = new HashMap<>();
        claims.put("id",1);
        claims.put("name","xiaoji");
        /**
         * builder:用来构建jwt令牌
         * signWith: 生成jwt令牌使用的数字算法(jwt.io),官网有,参数一指定算法,参数二就是签名秘钥,这个随便写,但是切记不要少于5个字符,否则报错
         * setClaims:设置自定义数据(载荷)
         * setExpiration:设置令牌有效期,System.currentTimeMillis()+3600 当前时间+3600秒,也就是3600*1000毫秒后令牌过期,就是设置有效期为一小时
         * compact:调用compact可以拿到一个字符串类型的返回值
         */
        String jinweizhe = Jwts.builder().signWith(SignatureAlgorithm.HS256, "jinweizhe").setClaims(claims).setExpiration(new Date(System.currentTimeMillis() + 3600*1000)).compact();
        System.out.println("生成的jwt为: "+jinweizhe); // 这个打印的就是jwt令牌
        // 生成的jwt为: eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoieGlhb2ppIiwiaWQiOjEsImV4cCI6MTcxNjIxODU2OH0.4-yMVfNWyb87TFryq8FJTiH_AAXLsmYGOFVybyjK15g
    }


    /**
     * 解析jwt
     */
    @Test
    void testGetJwt(){
   
        /**
         * setSigningKey:指定签名秘钥
         * parseClaimsJws:传入jwt令牌
         * getBody:拿到自定义内容
         */
        Claims jinweizhe = Jwts.parser().setSigningKey("jinweizhe").parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoieGlhb2ppIiwiaWQiOjEsImV4cCI6MTcxNjIxODU2OH0.4-yMVfNWyb87TFryq8FJTiH_AAXLsmYGOFVybyjK15g").getBody();
        System.out.println("解析到的jwt为: "+jinweizhe);  // 解析到的jwt为: {name=xiaoji, id=1, exp=1716218568}
    }
}
  • JWT校验时使用的签名秘钥,必须和生成IWT令牌时使用的秘钥是配套的
  • 如果JWT令牌解析校验时报错,则说明JWT令牌被篡改 或 失效了,令牌非法。

过滤器filter的使用操作

  • 定义Filter:定义一个类,实现 Filter 接口,并重写其所有方法。
  • 配置Filter:filter类上加 @WebFiter 注解,配置拦截资源的路径。引导类上加 @ServletComponentscan 开启Servlet组件支持,

登录校验流程

  • 获取请求url。
  • 判断请求url中是否包含login,如果包含,说明是登录操作,放行
  • 获取请求头中的令牌(token)
  • 判断令牌是否存在,如果不存在,返回错误结果(未登录)。
  • 解析token,如果解析失败,返回错误结果(未登录)
  • 放行。

在SpringBoot项目下,新建一个utils包和DemoFilter类

这里说明一下,下面用到的Result和JwtUtils都是工具包,下面有完整的项目代码,里面是有包含的,这里就不写出来了,可以往下翻找到完整项目代码

DemoFilter类内容如下

package com.jwz.login;


import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONWriter;
import jakarta.servlet.*;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import java.io.IOException;
@Slf4j
@WebFilter(urlPatterns = "/*")  // 拦截所有的请求
// @WebFilter(urlPatterns = "/emps/*") // 访问emps下的所有资源的,都会被拦截
// @WebFilter(urlPatterns = "/login") // 拦截具体接口
public class DemoFilter implements Filter {
   
    // 还有init和destroy分别对应初始化方法和销毁方法,都只会调用一次,这两个不用重写,因为查看Filter源码会发现底层已经默认调用了,当然,想重写也可以
    // 这里只关注doFilter即可,他会在拦截到请求之后开始调用,会调用多次
    @Override // 拦截到请求之后调用,会调用多次,拦截到接口需要放行,否则接口不返回数据
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
   
        // System.out.println("拦截到请求了...放行之前的逻辑");
        // // 放行接口
        // // 参数1:请求对象  参数2:响应对象
        // // 放行后可以发现能正常返回数据了
        // filterChain.doFilter(servletRequest,servletResponse);
        // System.out.println("拦截到请求了...放行之后的逻辑");


        // 下面是登录校验的实现思路
        HttpServletRequest req = (HttpServletRequest) servletRequest;
        HttpServletResponse resp = (HttpServletResponse) servletResponse;

        // 将请求头和响应头都设置utf-8的格式,避免请求和响应结果有中文造成了乱码
        req.setCharacterEncoding("UTF-8");
        resp.setCharacterEncoding("UTF-8");
        resp.setContentType("application/json; charset=UTF-8");

        //1.获取请求ur1.
        String url = req.getRequestURL().toString();
        log.info("请求的url:{}",url);
        //2.判断请求url中是否包含login,如果包含,说明是获录操作,放行。
        if(url.contains("login")){
   
            log.info("登录操作,直接放行");
            filterChain.doFilter(servletRequest,servletResponse);
            return; // 停止代码继续向下执行
        }
        //3.获取请求头中的令牌(token)。
        String token = req.getHeader("token");
        //4.判断令牌是否存在、如果不存在,返回错误结果(未发录)
        if(!StringUtils.hasLength(token)){
    // 判断字符串是否有长度
            log.info("请求头token为空,返回未登录信息");
            Result error = Result.error("未登录"); // 这里的Result是一个工具类,笔记下面的完整项目里面有工具文件代码
            // 手动转换 对象 -- json -----> 阿里巴巴fastJSON工具包(https://mvnrepository.com/artifact/com.alibaba.fastjson2/fastjson2/2.0.50)
            // 去上面地址复制代码到pom.xml依赖下载一下
            String noLogin = JSONObject.toJSONString(error); // 获取到json字符串(对象转成了json字符串)
            resp.getWriter().write(noLogin); // 将结果响应给浏览器
            return;
        }
        //5.解析token,如果解析失败,返回误结果(未录)
        // 这里的JwtUtils也是个工具类,跟上面的Result一样,下翻完整代码里面有工具类代码提供
        try {
   
            JwtUtils.parseJWT(token);
        } catch (Exception e) {
   
            // e.printStackTrace();
            log.info("令牌解析失败,返回未登录的错误信息");
            Result error = Result.error("未登录");
            String noLogin = JSONObject.toJSONString(error); // 获取到json字符串(对象转成了json字符串)
            resp.getWriter().write(noLogin); // 将结果响应给浏览器
            return;
        }
        //6.放行。
        log.info("令牌合法,直接放行");
        filterChain.doFilter(servletRequest, servletResponse);
    }
}

启动类新增一个注解

package com.jwz;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;

@ServletComponentScan // 开启了对servlet组件的支持
@SpringBootApplication
public class LoginVeifillyApplication {
   

    public static void main(String[] args) {
   
        SpringApplication.run(LoginVeifillyApplication.class, args);
    }

}

测试用的controller

package com.jwz.login;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

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

@Slf4j
@RestController
public class loginController {
   
    @PostMapping("/login")
    public Result login(@RequestBody loginEntity login){
   
        // 登陆成功,生成jwt并下发jwt返回给前端
            Map<String, Object> claims = new HashMap<>();
            claims.put("id",1);
            claims.put
  • 18
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

萧寂173

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值