JWT登录

文章详细描述了前端通过Web表单发送用户名和密码到后端,使用JWT进行安全认证的过程,包括JWT的生成、存储、以及如何在Filter和Interceptor中实现登录验证。同时,对比了Filter和Interceptor在处理请求和使用范围上的区别。
摘要由CSDN通过智能技术生成

**

认证流程

**
前端通过Web表单将自己的用户名和密码发送到后端的接口。该过程一般是HTTP的POST请求。建议的方式是通过SSL加密的传输(https协议),从而避免敏感信息被嗅探。
后端核对用户名和密码成功后,将用户的id等其他信息作为JWT Payload(负载),将其与头部分别进行Base64编码拼接后签名,形成一个JWT(Token)。
后端将JWT字符串作为登录成功的返回结果返回给前端。前端可以将返回的结果保存在localStorage(浏览器本地缓存)或sessionStorage(session缓存)上,退出登录时前端删除保存的JWT即可。
前端在每次请求时将JWT放入HTTP的Header中的Authorization位。(解决XSS和XSRF问题)HEADER
后端检查是否存在,如存在验证JWT的有效性。例如,检查签名是否正确﹔检查Token是否过期;检查Token的接收方是否是自己(可选)
验证通过后后端使用JWT中包含的用户信息进行其他逻辑操作,返回相应结果。

**

JWT结构

**
就是令牌token,是一个String字符串,由3部分组成,中间用点隔开

令牌组成:

标头(Header)
有效载荷(Payload)
签名(Signature)
token格式:head.payload.singurater 如:xxxxx.yyyy.zzzz

Header:有令牌的类型和所使用的签名算法,如HMAC、SHA256、RSA;使用Base64编码组成;(Base64是一种编码,不是一种加密过程,可以被翻译成原来的样子)

{
“alg” : “HS256”,
“type” : “JWT”
}

Payload :有效负载,包含声明;声明是有关实体(通常是用户)和其他数据的声明,不放用户敏感的信息,如密码。同样使用Base64编码

{
“sub” : “123”,
“name” : “John Do”,
“admin” : true
}
Signature :前面两部分都使用Base64进行编码,前端可以解开知道里面的信息。Signature需要使用编码后的header和payload,加上我们提供的一个密钥,使用header中指定的签名算法(HS256)进行签名。签名的作用是保证JWT没有被篡改过

**

引入依赖

**

		<!--JWT令牌-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>
        <!--toJson-->
    

因为filter不是spring框架提供的,所以返回Result类结果不会自动转为JSON格式,所以引入依赖来手动转换。

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

**

Filter过滤基本框架

**

@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 {
        //放行 访问资源
        filterChain.doFilter(servletRequest,servletResponse);
        //资源访问后还会回到本方法,并执行放行之后的逻辑
        //多个过滤器会产生过滤器链,访问过滤器顺序按照过滤器名字的字母排序
        System.out.println("after doFilter");
    }

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

定义一个filter实现Filter接口,有三个重写函数,初始化init,过滤操作doFilter,销毁操作destroy。
在doFilter中实现放行操作代码

 filterChain.doFilter(servletRequest,servletResponse);

**

运用filter和jwt实现登录操作

**

@WebFilter(urlPatterns = "/*")
public class LoginCheckFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest req=(HttpServletRequest) servletRequest;
        HttpServletResponse res=(HttpServletResponse) servletResponse;
        //获取url
        String url=req.getRequestURI().toString();
        //是否包含login
        if(url.contains("login")){
            filterChain.doFilter(servletRequest,servletResponse);
            return;
        }

        String jwt=req.getHeader("token");//jwt默认封装在前端请求header的token标签中
        
        //jwt是否为空
        if(jwt==null||jwt.equals("")){
            Result error = Result.error("NOT_LOGIN");
            String notLogin= JSONObject.toJSONString(error);
            res.getWriter().write(notLogin);
            return;

        }
        //不为空则解析jwt
        try{
            JwtUtils.parseJWT(jwt);
        } catch (Exception e) {
            e.printStackTrace();
            Result error = Result.error("NOT_LOGIN");
            String notLogin= JSONObject.toJSONString(error);
            res.getWriter().write(notLogin);
            return;

        }
        //jwt正确则放行
        filterChain.doFilter(servletRequest,servletResponse);
    }
}

资源访问后还会回到本方法,并执行放行之后的逻辑
多个过滤器会产生过滤器链,访问过滤器顺序按照过滤器名字的字母排序

**

Interceptor实现

**

@Component
public class LoginCheckInterceptor implements HandlerInterceptor {
    @Override//为true代表放行
    public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) throws Exception {
        //获取url
        String url=req.getRequestURI().toString();
        //是否包含login
        if(url.contains("login"))   return true;


        String jwt=req.getHeader("token");
        //jwt是否为空
        if(jwt==null||jwt.equals("")){
            Result error = Result.error("NOT_LOGIN");
            String notLogin= JSONObject.toJSONString(error);
            res.getWriter().write(notLogin);
            return false;

        }
        //不为空则解析jwt
        try{
            JwtUtils.parseJWT(jwt);
        } catch (Exception e) {
            e.printStackTrace();
            Result error = Result.error("NOT_LOGIN");
            String notLogin= JSONObject.toJSONString(error);
            res.getWriter().write(notLogin);
            return false;

        }
        return true;
    }
}
@Configuration
public class Webconfig implements WebMvcConfigurer {
    @Autowired
    private LoginCheckInterceptor loginCheckInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // /*代表一级路径  /**代表任意一级路径
        registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**").excludePathPatterns("/login");
    }
}

**

  • preHandle() :这个方法将在请求处理之前进行调用。注意:如果该方法的返回值为false
    ,将视为当前请求结束,不仅自身的拦截器会失效,还会导致其他的拦截器也不再执行。
  • postHandle():只有在 preHandle() 方法返回值为true 时才会执行。会在Controller
    中的方法调用之后,DispatcherServlet 返回渲染视图之前被调用

Filter和Interceptor有什么区别?

**
在这里插入图片描述
Filter会拦截所有资源,而Interceptor只会拦截Spring相关资源
Filter先于Interceptor调用,Interceptor介于Servlet和Controller之间。

1、实现原理不同
过滤器和拦截器 底层实现方式大不相同,过滤器 是基于函数回调的,拦截器 则是基于Java的反射机制(动态代理)实现的。

2、使用范围不同
我们看到过滤器 实现的是 javax.servlet.Filter 接口,而这个接口是在Servlet规范中定义的,也就是说过滤器Filter 的使用要依赖于Tomcat等容器,导致它只能在web程序中使用。
在这里插入图片描述
而拦截器(Interceptor) 它是一个Spring组件,并由Spring容器管理,并不依赖Tomcat等容器,是可以单独使用的。不仅能应用在web程序中,也可以用于Application、Swing等程序中。
在这里插入图片描述

3、触发时机不同
过滤器Filter是在请求进入容器后,但在进入servlet之前进行预处理,请求结束是在servlet处理完以后。
拦截器 Interceptor 是在请求进入servlet后,在进入Controller之前进行预处理的,Controller 中渲染了对应的视图之后请求结束。

4、拦截的请求范围不同
过滤器几乎可以对所有进入容器的请求起作用,而拦截器只会对Controller中请求或访问static目录下的资源请求起作用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值