给朋友做的相册网站没有了,如何进行营销型企业网站的优化,怎么做电商网站 用户画像,网站建设阐述统一拦截
上文我们提到#xff08;登录认证#xff08;4#xff09;#xff1a;令牌技术#xff09;#xff0c;现在大部分项目都使用JWT令牌来进行会话跟踪#xff0c;来完成登录功能。有了JWT令牌可以标识用户的登录状态#xff0c;但是完整的登录逻辑如图所示…统一拦截
上文我们提到登录认证4令牌技术现在大部分项目都使用JWT令牌来进行会话跟踪来完成登录功能。有了JWT令牌可以标识用户的登录状态但是完整的登录逻辑如图所示 我们还需要一个统一拦截器用于拦截用户的请求在拦截器中我们需要验证用户的JWT令牌来判断用户是否登录从而进行放行或拦截。统一拦截一般有两种解决方案Filter过滤器和Interceptor拦截器本文先讲解Filter过滤器。
Filter过滤器
工作原理
Filter的本意就是过滤器在JavaWeb中是用于过滤请求的是JavaWeb的三大核心组件之一 Servlet、Filter、Listener。Filter过滤器的工作原理就是将客户端发起的对服务端资源的请求拦截下来进行处理从而实现一些特殊功能。 当程序使用了Filter过滤器之后请求想要访问服务端的资源就必须先经过过滤器待过滤器处理完毕放行之后才可以访问对应的资源。Filter过滤器一般用于完成一些通用的操作比如登录校验、敏感字符处理等。
快速入门
Filter过滤器的快速入门十分简单主要步骤分为两步首先需要定义过滤器定义一个类实现Filter接口并重写其中所有方法然后需要配置过滤器在Filter类上添加WebFilter注解配置拦截资源的路径只有请求对应的资源才会被过滤器拦截。假如使用SpringBoot构建项目还需要在引导类上添加ServletComponentScan注解开启Servlet组件支持。
定义过滤器
定义Filter过滤器的代码
public class DemoFilter implements Filter {Overridepublic void init(FilterConfig filterConfig) throws ServletException {log.info(Init Filter);}Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {log.info(Filter 成功拦截请求);}Overridepublic void destroy() {log.info(Destroy Filter);}
}定义Filter过滤器的代码很简单首先需要定义一个类实现Filter接口然后重写Filter接口中的三个方法。
init方法
顾名思义init方法是Filter过滤器的初始化方法在服务器启动时会自动创建Filter过滤器对象在创建过滤器对象的时候就会自动调用init初始化方法初始化过滤器并且这个方法只会被调用一次。
doFilter方法
doFilter方法是过滤器的核心部分该方法在过滤器每一次拦截到了请求之后都会被调用一般而言这个方法会被调用多次每一次拦截到请求都会调用一次doFilter方法而我们就可以在doFilter方法中实现一些功能比如说对这次请求的JWT令牌进行解析以此判断用户的登录状态。
destroy方法
destroy方法是销毁过滤器的方法当服务器关闭时会自动调用destroy方法销毁过滤器destroy方法也只会被调用一次。
配置过滤器
在定义Filter过滤器之后过滤器并不会生效此时还需要完成Filter过滤器的配置过滤器的配置相对简单只需要在Filter类上添加WebFilter注解并在其urlPatterns属性中指定需要拦截的请求路径。
Slf4j
WebFilter(urlPatterns /*) // 配置Filter过滤器的拦截请求路径/*表示拦截所有
public class DemoFilter implements Filter {Overridepublic void init(FilterConfig filterConfig) throws ServletException {log.info(Init Filter);}Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {log.info(Filter 成功拦截请求);}Overridepublic void destroy() {log.info(Destroy Filter);}
}通过/*通配符表示拦截所有请求所有请求都会被过滤器所拦截可以根据不同的需求更改路径这样就完成了Filter过滤器的配置当定义和配置都完成之后Filter过滤器就可以真正开始工作了此时启动服务器进行测试 如图所示在服务器启动的时候自动创建Filter过滤器并调用了其init方法初始化过滤器。此时向服务端发起请求 如图所示发起的请求成功被Filter过滤器拦截但是客户端并没有得到服务器响应的数据 这是因为在Filter过滤器中必须要执行放行操作才可以访问到服务器中的资源可以通过FilterChain实体类中的doFilter方法放行
Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {log.info(Filter 成功拦截请求);filterChain.doFilter(servletRequest, servletResponse);
}放行之后再发起请求就可以成功访问到服务器中的资源了 关闭服务器发现Filter过滤器自动调用destroy方法销毁 登录校验过滤器
通过上文的快速入门我们已经了解了如何创建并配置一个Filter过滤器那么回归到主线使用Filter过滤器完成登录校验功能。 实现逻辑
让我们回顾一下登录校验的实现逻辑用户登录时需要访问登录接口login当用户输入的用户名和密码验证成功之后会生成一个JWT令牌并且将JWT令牌返回给客户端客户端会将JWT存储起来然后在后续的每一次请求中都携带这个JWT令牌到服务端这个时候就需要Filter过滤器进行工作了在登录校验中Filter过滤器必须要验证JWT令牌的有效性如果令牌能够成功解析则证明为有效令牌反之则为无效令牌。若令牌有效Filter过滤器则放行请求让它访问服务端对应的资源如果为无效令牌则进行拦截并给客户端响应一个错误的信息401。其流程如图所示 这样登录校验的实现逻辑已经比较清晰了但需要注意一点对于登录login请求过滤器是不需要进行拦截的因为用户发起登录请求就是为了获得JWT令牌其本身是没有JWT令牌的如果进行拦截那么永远都只会得到请求失败的结果。
我们上述逻辑编写登录校验过滤器代码
/*** 令牌校验过滤器登录过滤器*/
Slf4j
WebFilter(urlPatterns /*)
public class LoginFilter implements Filter {Overridepublic void init(FilterConfig filterConfig) throws ServletException {log.info(Init Filter);}Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {HttpServletRequest httpServletRequest (HttpServletRequest) servletRequest;HttpServletResponse httpServletResponse (HttpServletResponse) servletResponse;// 获取该请求的URLString url httpServletRequest.getRequestURL().toString();// 判断该请求是否包含login如果包含说明该请求是登录则放行if (url.contains(/login)) {log.info(login);filterChain.doFilter(httpServletRequest, httpServletResponse);return;}// 获取请求头中的tokenJWT令牌String jwt httpServletRequest.getHeader(token);// 判断令牌是否存在若不存在则返回错误结果未登录if (jwt null || jwt.isEmpty()) {log.info(JWT令牌为空登录失败);httpServletResponse.setStatus(401);return;}// 解析JWT令牌如果解析失败则返回错误结果未登录try {JWTUtils.parseJWT(jwt);} catch (Exception e) {e.printStackTrace();log.info(JWT解析失败登录失败);httpServletResponse.setStatus(401);return;}// 令牌解析成功放行log.info(令牌解析成功放行);filterChain.doFilter(httpServletRequest, httpServletResponse);}Overridepublic void destroy() {log.info(Destroy Filter);}
}我们配置的过滤器是会拦截所有的请求但是这和我们分析的逻辑不一样我们需要直接放行登录请求所以说需要进行判断该请求是否是登录可以根据请求路径进行判断。然后需要获取到这次请求的token如果请求没有一个请求头叫token那么可以判断该请求没有携带JWT令牌表示该用户没有登录所以说直接响应错误结果无需进行判断最后才是解析token假如在解析过程中报错那么肯定意味着JWT令牌解析错误意味着用户可能伪造或更改了令牌也表示用户未登录所以说不能放行需要返回错误代码。如果成功解析JWT令牌那么就可以调用FilterChain中的doFilter方法放行该请求让它访问服务端对应的资源。这就是 登录校验 的整个流程。此时让我们发起请求进行测试 如图所示发起了一个非登录的请求由于此时还没有登录所以说没有JWT令牌所以说自然被Filter过滤器所拦截请求失败。 此时发起登录请求由于我们的逻辑是登录请求直接放行所以说这次请求就被Filter过滤器放行了成功获得了JWT令牌。 当我们登录后获得了JWT令牌之后的请求就可以在请求头中携带JWT令牌发起请求这样当我们的JWT令牌是正确的被成功解析之后Filter过滤器就会放行就可以访问到对应的资源了。
Filter过滤器使用细节
Filter过滤器执行流程
Filter过滤器执行流程如图所示 当过滤器拦截到了请求之后如果希望该请求访问到服务端资源那么就需要执行doFilter方法进行放行在doFilter方法所编写的代码就是放行前逻辑。但是值得注意的是——请求访问完资源之后还会回到过滤器当中如果有需求回到过滤器之后还可以执行放行后逻辑放行后逻辑就是doFilter方法之后的代码。
Filter过滤器拦截路径
可以根据不同的需求配置不同的拦截路径下面介绍几种常见的拦截路径像/login这样的拦截路径属于具体拦截路径只有请求路径为/login时拦截器才会拦截像/emps/*这样的拦截路径属于目录拦截访问/emps下的所有资源的请求都会被拦截像/*这样的拦截路径十分简单粗暴会拦截所有请求。可以根据不同的需求灵活的配置拦截路径。
过滤器链
在一个web应用程序中可以根据需求配置多个拦截器这样的多个拦截器就形成了一个过滤器链 如图所示在web服务端中定义了两个Filter过滤器这两个过滤器就形成了一个过滤器链过滤器链上的过滤器会一个一个的执行先执行第一个再执行第二个必须要过滤器链上的最后一个过滤器放行后也代表着所有过滤器都必须放行请求才能访问到对应的资源。但是当请求返回时会根据相反的顺序通过过滤器链先执行过滤器2再执行过滤器1最后给客户端响应数据。
并且过滤器链的执行顺序是根据过滤器名字符串的自然排序的比如AbcFilter会先于DemoFilter执行。
总结
Filter过滤器是Servlet中的技术是用于统一拦截的想要在web程序中使用过滤器就需要定义一个过滤器并且配置过滤器定义其拦截路径我们可以在Filter过滤器的doFilter方法中编写一些逻辑决定该过滤器的放行逻辑从而实现登录校验功能。Spring框架中也提供了一个类似过滤器的Interceptor拦截器且听下回分解。