Cookie & Session & JWT认证 & Filter & Interceptor

文章目录

  • 前言
  • 一、Cookie和Session
  • 二、JWT
    • 1.三部分
    • 2.使用
    • 3.另外一种使用
      • 3.1引入依赖
      • 3.1 定义工具类
  • 三、Filter过滤器
    • 3.1 实现Filter接口,并且增加@WebFilter注解
    • 3.2 启动类上增加注解
    • 3.3Filter过滤实现登陆校验
    • 3.4拦截器实现登陆校验
  • 总结


前言

本文介绍了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.jsonwebtokengroupId>
            <artifactId>jjwtartifactId>
            <version>0.9.1version>
        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.auth0groupId>
            <artifactId>java-jwtartifactId>
            <version>4.4.0version>
        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.alibabagroupId>
         <artifactId>fastjsonartifactId>
         <version>2.0.28version>
     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.bindgroupId>
            <artifactId>jaxb-apiartifactId>
            <version>2.3.1version>
        dependency>

你可能感兴趣的:(java,spring,spring,boot)