博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Filter——拦截请求保护页面安全
阅读量:4090 次
发布时间:2019-05-25

本文共 3687 字,大约阅读时间需要 12 分钟。

——拦截请求保护页面安全 由发表在

在处理创建文章表单的Servlet中,创建了一个Post对象,它的成员变量User被设置为当前Session中的user属性。从业务逻辑的角度来说,那么在创建文章时必须保证当前用户已经登录,对于没有登录的用户,不应该让它看到创建文章的表单页面。

为了实现这样的需求,我们可以直接在Servlet中编写类似逻辑:

User user = (User) req.getSession().getAttribute("user");if (user == null) {    resp.sendError(HttpServletResponse.SC_FORBIDDEN, "no user in session");}

SC_FORBIDDENHttpServletResponse中定义的一个常量,它的值是403,这里的sendError函数相当于向浏览器返回一个403 Forbidden的状态码以及权限错误信息。

这一类需求在Web应用中非常的常见,尤其是多用户系统中用户身份的认证以及权限控制愈发重要。例如用户A不能访问用户B的文章管理页面并篡改B的文章。当我们的Web应用页面越来越多,需要类似权限控制的逻辑愈发复杂时,如果还在每一个Servlet中去编写这样的逻辑,不仅会出现大量重复的代码(可能很多页面的控制逻辑是相同的——例如用户已经登录才能访问),而且也违背了软件设计模式中的单一职责原则,Servlet既需要考虑处理HTTP请求,同时还需要考虑权限控制。

在Filter中实现权限控制逻辑

解决上面提到问题的办法其实也很简单——把权限控制逻辑从Servlet组件中提取出来,另外作为一种可复用的组件——不仅Servlet的权限控制可以使用,而且今后其它需要用到权限控制的地方同样可以用到。这样做的好处就是把Servlet的职责清晰化,并且和权限控制逻辑解耦。

Filter是Servlet规范中非常有用的组件。Filter被用于在Servlet/JSP等资源处理HTTP请求之前,对请求进行拦截处理,下图是Filter拦截HTTP请求的过程:

Filter在Servlet/JSP之前对HTTP请求进行拦截,可以同时存在多个Filter组成Filter链(Chain),在任意Filter中可以决定继续执行Filter链中的下一个Filter,还是把response直接返回到浏览器。Filter链全部执行完成后,HTTP请求才会到达相应的Servlet/JSP中。以下是Servlet规范中Filter接口的定义:

public interface Filter {    public void init(FilterConfig filterConfig) throws ServletException;    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException;    public void destroy();}

Servlet类似,Filter接口也需要实现生命周期中的init()destroy()方法。它最重要的方法是doFilter(),在该方法中可以拿到requestresponse对象并执行相应的逻辑。

下面我们把创建博文需要登录的逻辑放在Filter中:

@WebFilter(filterName = "createPostFilter", urlPatterns = "/createPost")public class CreatePostFilter implements Filter {    @Override    public void destroy() {    }    @Override    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain filterChain)            throws IOException, ServletException {        HttpServletRequest request = (HttpServletRequest) req;        User user = (User) request.getSession().getAttribute("user");        if (user == null) {            resp.sendError(HttpServletResponse.SC_FORBIDDEN, "no user in session");            return;        }        filterChain.doFilter(req, resp);    }    @Override    public void init(FilterConfig arg0) throws ServletException {    }}
  • @WebFilter(filterName = "createPostFilter", urlPatterns = "/createPost")表示CreatePostFilter应该被Servlet容器作为一个Filter加载,它拦截所有URL路径为/createPost的请求(包括GET和POST请求)。
  • 如果用户不存在,直接返回HTTP状态码403;如果存在,调用filterChain.doFilter(req,resp)继续执行Filter链中的下一个Filter。

这样我们把处理HTTP请求的业务逻辑放在了Servlet中,把权限控制的逻辑放在了Filter中,二者各司其职并且都是可以被复用的组件。

优化登录流程

在上一节描述的保护页面中,如果用户没有登录,直接通过URL(虽然无法从页面直接点击过去,但是可以在浏览器中直接输入)访问文章创建页面,那么它会得到一个Tomcat容器默认的错误提示页面,提示用户无权限访问。当用户看到这个错误提示页面,它可能会有多种选择——可能会回退到上一个页面,可能会关闭页面重新打开,无论哪种情况体验似乎都不友好。

其实这个过程可以优化为:如果用户尚未登录却访问了一个需要登录的页面,就先跳转到登录页面,用户登录成功后再跳转到他之前想要访问的目标页面,整个过程示意如下:

整个过程的重点就是在重定向到登录页面时在登录页面的url后面戴上了一个名字为next的参数,这个参数代表着目标页面的url。一旦登录成功,处理登录请求的Servlet就会重定向到该url。

实现:Filter

在Filter中只需要通过request.getRequestURI()获取当前受保护页面的url,将其作为参数重定向:

@Overridepublic void doFilter(ServletRequest req, ServletResponse resp, FilterChain filterChain)        throws IOException, ServletException {    HttpServletRequest request = (HttpServletRequest) req;    User user = (User) request.getSession().getAttribute("user");    if (user == null) {        HttpServletResponse response = (HttpServletResponse) resp;        response.sendRedirect("/ServletBlogDemo/account/login?next=" + request.getRequestURI());        return;    }    filterChain.doFilter(req, resp);}

实现:Servlet

LoginController中需要获取next参数并进行跳转:

//如果登录成功String next = req.getParameter("next");if (next == null || next.isEmpty()) {    resp.sendRedirect("/ServletBlogDemo/userPosts?username=" + user.getUsername());} else {    resp.sendRedirect(next);}

更多文章请访问

你可能感兴趣的文章
在《我的世界》里从零打造一台计算机有多难?复旦本科生大神花费了一年心血...
查看>>
刷了几千道算法题,这些我私藏的刷题网站都在这里了!
查看>>
做程序员 10 年了,复制粘贴是我最牛逼的技能,直到看了这些大佬分享的公众号干货内容......
查看>>
来,教你做个属于自己的 Markdown 编辑器(代码开源)!
查看>>
废旧 Android 手机如何改造成 Linux 服务器
查看>>
2019 年不可错过的 45 个 AI 开源工具
查看>>
GitHub 上有哪些适合新手跟进的优质项目?
查看>>
IPV4 地址耗尽会对互联网产生什么影响?
查看>>
除了 iTerm,这款高颜值的终端工具也很赞!
查看>>
955 不加班的公司名单:955.WLB
查看>>
2019 年最全 IT 吃瓜指南
查看>>
推荐一位大神,手握 GitHub 16000 star
查看>>
GitHub 上有个沙雕开发者,做了款斗图工具后火了...
查看>>
这才是真正的 Git:Git 内部原理揭秘!
查看>>
微软花2个亿做出来的软件免费用!网友:太良心了!
查看>>
硬核! 逛了 4 年 GitHub,一口气把我收藏的 Java 开源项目分享给你!
查看>>
牛逼!这家 AI 公司用面具破解了中国的人脸识别系统!微信、支付宝、火车站无一幸免...
查看>>
看完 GitHub 上这几个奇葩项目后,我忍不住笑了 233333
查看>>
她改变了编程
查看>>
B站收藏 6.1w+!GitHub 标星 3.9k+!这门神课拯救了我薄弱的计算机基础
查看>>