Cookie & Session & JWT认证 & Filter & Interceptor


前言

本文介绍了Cookie,Session,JWT,过滤器,拦截器的相关知识


一、Cookie和Session

	 浏览器请求头携带Cookie;
	服务器响应头Set-Cookie;
	进行会话跟踪。
	但是移动端APP,用户禁用,跨域情况下,Cookie失效。
	跨域:协议、IP/域名、端口不一样,前端请求时,出现跨域
	
	Session:
	浏览器请求头的Cookie中携带JSessionId;
	服务器响应头的Cookie中有JSessionId
	服务器集群需要处理Session共享的问题

二、JWT

1.三部分

分为以下三个部分,Header和PayLoad使用Base64编码
Header:存储令牌类型,加密算法。比如{“alg”: “HS256”, “type”: “JWT”}
PayLoad :Json格式的数据。比如:{“userId”: 1}
Signature: 签名,对Header,PayLoad根据加密算法进行加密

2.使用

pom.xml引入依赖:

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

JWT加解密单元测试:

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.junit.jupiter.api.Test;

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

public class JwtTest {

    @Test
    public void testBuildJwt(){

        Map<String, Object> claims = new HashMap<>();
        claims.put("username", "zhangsan");
        claims.put("job", "developer");
        String compact = Jwts.builder()
                //设置有效载荷
                .setClaims(claims)
                //设置签名
                .signWith(SignatureAlgorithm.HS256, "123456")
                .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24 * 7))
                .compact();
        System.out.println(compact);
    }

    @Test
    public void testParseJwt(){

        Claims body = Jwts.parser()
                .setSigningKey("123456")
                .parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJqb2IiOiJkZXZlbG9wZXIiLCJleHAiOjE3MTMzMjE0MjQsInVzZXJuYW1lIjoiemhhbmdzYW4ifQ.R9H8nncSCooaffujgxlCk3vuikkE-sH9j8ATGWQu-y8")
                .getBody();
        System.out.println(body);

    }

}

3.另外一种使用

3.1引入依赖

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

3.1 定义工具类

定义配置文件类,这里定义配置文件中,前缀为jwt,变量名称成secret的变量。
配置文件中配置:jwt.secret=xxx

package com.web.springbootall.property;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix = "jwt")
@Data
public class JwtSecretProperty {

    private String secret;

}

定义工具类

package com.web.springbootall.util;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.web.springbootall.property.JwtSecretProperty;
//import io.jsonwebtoken.Claims;
//import io.jsonwebtoken.Jwts;
//import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

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

@Component
public class JwtUtil {

    @Autowired
    private JwtSecretProperty jwtSecretProperty;

    public String generate(Map<String, Object> claims) {

        return JWT.create().withClaim("user", claims).withExpiresAt(new Date(System.currentTimeMillis() + 1000 * 3600))
                .sign(Algorithm.HMAC256(jwtSecretProperty.getSecret()));
//        return Jwts.builder().setClaims(claims).signWith(SignatureAlgorithm.HS512, jwtSecretProperty.getSecret())
//                .setExpiration(new Date(System.currentTimeMillis() + 1000 * 3600)).compact();
    }

    public Claim parse(String token) {
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(jwtSecretProperty.getSecret())).build();
        return jwtVerifier.verify(token).getClaim("user");
//        return Jwts.parser().setSigningKey(jwtSecretProperty.getSecret()).parseClaimsJws(token).getBody();
    }

}

三、Filter过滤器

3.1 实现Filter接口,并且增加@WebFilter注解

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

@WebFilter(urlPatterns = "/*")
public class DemoFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        // 过滤器的业务逻辑
        System.out.println("DemoFilter doFilter");
        // 放行
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}

3.2 启动类上增加注解

@ServletComponentScan

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

@ServletComponentScan
@SpringBootApplication
public class TliasWebManagementApplication {

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

}

3.3Filter过滤实现登陆校验

引入JSON依赖:

     <dependency>
         <groupId>com.alibaba</groupId>
         <artifactId>fastjson</artifactId>
         <version>2.0.28</version>
     </dependency>

过滤器实现登陆验证:

import com.alibaba.fastjson.JSON;
import com.qinjie.tliaswebmanagement.domain.Result;
import com.qinjie.tliaswebmanagement.util.JwtUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

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

@WebFilter(urlPatterns = "/*")
@Slf4j
public class LoginFilter implements Filter {

    @Autowired
    private JwtUtil jwtUtil;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //如果不是登陆接口,并且token不对,则拦截,退出
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        if (!request.getRequestURI().equals("/login")){
            String token = request.getHeader("token");
            Claims claims = null;
            try {
                claims = jwtUtil.parse(token);
            } catch (Exception e) {
                log.error("令牌解析失败,token:{}", token, e);
            }
            if (token == null || claims == null){
                Result notLogin = Result.fail("NOT_LOGIN");
                String notLoginString = JSON.toJSONString(notLogin);
                servletResponse.getWriter().write(notLoginString);
                return;
            }
        }
        // 放行
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}

3.4拦截器实现登陆校验

定义Spring管理(@Component)的类,实现HandlerInterceptor接口的preHandle方法,返回true放行

import com.alibaba.fastjson.JSON;
import com.qinjie.tliaswebmanagement.domain.Result;
import com.qinjie.tliaswebmanagement.util.JwtUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {

    @Autowired
    private JwtUtil jwtUtil;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (!request.getRequestURI().equals("/login")){
            String token = request.getHeader("token");
            Claims claims = null;
            boolean hasToken = StringUtils.hasLength(token);
            try {
                if (hasToken) {
                    claims = jwtUtil.parse(token);
                }
            } catch (Exception e) {
                log.error("令牌解析失败,token:{}", token, e);
            }
            if (!hasToken || claims == null){
                Result notLogin = Result.fail("NOT_LOGIN");
                String notLoginString = JSON.toJSONString(notLogin);
                response.getWriter().write(notLoginString);
                return false;
            }
        }
        return true;
    }

}

定义MVC配置类(@Configuration),实现WebMvcConfigurer接口的addInterceptors方法,将拦截器加入其中(addInterceptor),设定拦截路径addPathPatterns,放行路径excludePathPatterns。比如下面将/login放行

import com.qinjie.tliaswebmanagement.interceptor.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private LoginInterceptor loginInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns("/login", "/css/**", "/js/**", "/fonts/**", "/images/**");
    }
}

过滤器在DispatcherServlet前执行,可以拦截所有资源;
拦截器在DispatcherServlet后执行,仅拦截Spring的资源。


总结

过滤器和拦截器可以用来做登陆校验,登陆过才放行请求到接口,而不需要所有接口都加上校验逻辑。
出现报错:
Handler dispatch failed: java.lang.NoClassDefFoundError: javax/xml/bind/DatatypeConverter
添加JWT相关的依赖:

	 	<dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.1</version>
        </dependency>
ESP32-S3在STA模式下设置静态IP通常涉及到配置网络接口的接口配置结构体,比如`esp_netif_t`。以下是一个基本步骤: 1. 首先,你需要在你的应用程序初始化阶段包含必要的头文件,如`esp_wifi.h``esp_netif.h`。 ```c #include &quot;esp_wifi.h&quot; #include &quot;esp_netif.h&quot; ``` 2. 定义你的静态IP、子网掩码、默认网关DNS服务器地址。例如: ```c static const char* ssid = &quot;your_SSID&quot;; static const char* password = &quot;your_PASSWORD&quot;; static ip4_addr_t static_ip = { IP4_ADDR(192, 168, 1, 100) }; // 你的静态IP static ip4_addr_t subnet_mask = { IP4_ADDR(255, 255, 255, 0) }; static ip4_addr_t gateway = { IP4_ADDR(192, 168, 1, 1) }; static ip4_addr_t dns_server = { IP4_ADDR(8, 8, 8, 8)}; // 示例DNS服务器地址 ``` 3. 初始化WiFi模块,并连接到指定的SSID: ```c esp_err_t ret = esp_wifi_init(); if (ret == ESP_OK) { wifi_config_t wifi_config = { .sta = { .ssid = ssid, .password = password, .bssid_set = false, // 如果你知道AP的BSSID可以设置为true }, }; ret = esp_wifi_set_mode(WIFI_MODE_STA); if (ret == ESP_OK) { ret = esp_wifi_start(); if (ret == ESP_OK) { // 等待WiFi连接成功 while (!esp_wifi_get_connect_status() == WIFI_STATUS_CONNECTED) { vTaskDelay(pdMS_TO_TICKS(500)); } } } // 连接成功后再配置静态IP } ``` 4. 创建并配置静态IP网络接口: ```c esp_netif_create StaIf, NULL, &amp;espnetif sta_if; if (esp_netif_create_data斯塔If(&amp;sta_if)) { esp_netif_set_ip4(&amp;sta_if, &amp;static_ip, &amp;subnet_mask, &amp;gateway); esp_netif_set_dhcp_client_data(&amp;sta_if, NULL); // 关闭DHCP服务,使用静态IP esp_netif_set_dns_server_num(&amp;sta_if, 1, &amp;dns_server); esp_netif_start(&amp;sta_if); } // 然后你可以开始发送接收数据包了 ``` 记得检查错误代码`esp_err_t`,处理可能出现的问题。此外,如果ESP32-S3需要访问互联网,你还可能需要配置路由器的端口转发规则。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值