EE Servlet 3:使用会话和过滤器开发用户登录

我在上一篇文章中介绍了Application类,您可以在其中设置后端服务。 我添加的一个示例服务是UserService 。 该服务将加载包含用户名和密码集的Java用户属性文件; 稍后将用于对用户进行身份验证以登录到Web应用程序。 现在,我将展示如何使用标准Servlet API以及此后端服务完成登录部分。

从高层次上讲,我们希望将某些Web资源(这意味着Servlet提供的某些URL,例如“ / sysprops”或“ / user”)限制为仅在我们的用户属性文件中已知的客户端用户。 用户可以使用匹配的密码来标识自己。 通常使用用户登录表单来完成此操作,对其进行身份验证,然后将登录令牌插入Http Session范围空间。 然后可以使用该登录令牌来验证是否允许用户访问受限资源。 我们只对单一授权感兴趣(未定义任何角色,任何登录的用户都可以访问任何受保护的URL。)

SysPropsServlet提供的我以前的SysPropsServlet ,您已经看到了一个映射到“ / sysprops” URL的示例,该示例仅生成系统信息HTML表。 这些是敏感信息,因此我们要保护此URL。 我们将需要创建一个实现javax.servlet.Filter接口的类,然后使用此过滤器添加“ / sysprops” URL,以便它可以在实际的Servlet之前对请求进行预处理。 此过滤器使我们可以检查HTTP请求对象并在需要时中止请求,从而限制了访问。

package zemian.servlet3example.web;import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import zemian.service.logging.Logger;@WebFilter(urlPatterns={"/sys-props", "/user"})
public class LoginRequiredFilter implements Filter {private static final Logger LOGGER = new Logger(LoginRequiredFilter.class);public static final String LOGIN_REDIRECT = "LOGIN_REDIRECT";@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {if (request instanceof HttpServletRequest) {HttpServletRequest req = (HttpServletRequest) request;LOGGER.trace("Checking LoginSession token for uri=%s", req.getRequestURI());LoginSession loginSession = LoginServlet.getOptionalLoginSession(req);if (loginSession == null) {LOGGER.debug("No LoginSession token found; forwarding request to login page.");// We need to save the old URI so we can auto redirect after login.req.setAttribute(LOGIN_REDIRECT, req.getRequestURI());req.getRequestDispatcher("/login").forward(request, response);return;} else {LOGGER.debug("Request allowed using LoginSession token=%s", loginSession.getId());}}chain.doFilter(request, response);}@Overridepublic void destroy() {}}

请注意,您可以配置此过滤器以匹配要保护的多个URL。 您甚至可以使用通配符模式,例如“ / *”,它将保护您应用程序中的每个URL! 过滤器只是在Http Session空间中LoginSession我们稍后将创建的LoginSession对象。 如果找到它,则它使请求通过,否则它将重定向到LoginServlet页面,该页面由LoginServlet类提供服务(请注意RETURN语句将提前退出filter方法,而无需调用filter链!)。

LoginServlet类是一种表单处理Servlet,它将提示用户输入用户名和密码。 如果成功,那么我们将LoginSession令牌对象插入到HttpSession空间中,这就是上面的过滤器正在寻找的内容。 这是处理Servlet代码。

package zemian.servlet3example.web;import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import zemian.service.logging.Logger;
import zemian.servlet3example.service.Application;
import zemian.servlet3example.service.UserService;@WebServlet("/login")
public class LoginServlet  extends HtmlWriterServlet {private static final Logger LOGGER = new Logger(LoginServlet.class);@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {HtmlWriter html = createHtmlWriter(req, resp);String message;// Check to see if we are doing logout or not.LoginSession loginSession = getOptionalLoginSession(req);if (loginSession != null && req.getParameter("logout") != null) {logout(req);message = "Your have successfully logged out.";} else {   message = (String)req.getAttribute("message");if (message == null)message = "";}  // Show a login formString redirectUri = (String)req.getAttribute(LoginRequiredFilter.LOGIN_REDIRECT);String redirectHtmlTag = "";if (redirectUri != null) {redirectHtmlTag = "<input type='hidden' name='redirectUri' value='" + redirectUri + "'/>";}html.header().h(1, "Please Login").p(message).println("<form method='post' action='login'>").println(redirectHtmlTag).println("<p/>Username: <input type='text' name='username'/>").println("<p/>Password: <input type='password' name='password'/>").println("<p/><input type='submit' value='Submit'/>").println("</form>").footer();}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {LOGGER.debug("Processing login form.");if (login(req)) {// Login succeed, we should auto redirect user if exists.String redirectUri = req.getParameter("redirectUri");if (redirectUri != null) {LOGGER.debug("Redirect after login to: %s", redirectUri);resp.sendRedirect(redirectUri);return;}}// Show the form again in case login failed or user didn't provide a redirectdoGet(req, resp);}   protected LoginSession createLoginSession(HttpServletRequest req, String username) {LoginSession result = new LoginSession(username);req.getSession(true).setAttribute(LoginSession.LOGIN_SESSION_KEY, result);return result;}protected void removeLoginSession(HttpServletRequest req) {HttpSession session = req.getSession(false);if (session != null) {session.removeAttribute(LoginSession.LOGIN_SESSION_KEY);}}private boolean login(HttpServletRequest req) throws IOException {String username = req.getParameter("username");String password = req.getParameter("password");UserService userService = Application.getInstance().getUserService();if (userService.validate(username, password)) {LOGGER.info("User %s logged in successfully.", username);// Create Session Data here after successful authenticated.LoginSession loginsession = getOptionalLoginSession(req);if (loginsession == null) {createLoginSession(req, username);req.setAttribute("message", "You have successfully logged in.");} else {req.setAttribute("message", "You already have logged in.");            }} else {LOGGER.info("User %s failed to login.", username);req.setAttribute("message", "Invalid login.");}return true;}/** Return LoginSession if found in HttpSession scope, else return NULL value. */public static LoginSession getOptionalLoginSession(HttpServletRequest req) {LoginSession result = null;HttpSession session = req.getSession(false);if (session != null)result = (LoginSession)session.getAttribute(LoginSession.LOGIN_SESSION_KEY);return result;}
}

LoginServlet类中,我们使用UserService服务来验证用户名和密码。 我们显示带有GET请求的登录表单,然后使用POST操作处理登录。 检查用户名和密码后,我们将创建LoginSession对象。 这只是表示会话令牌的简单POJO。 您可以保留所需的任何用户信息。 我不会在这里列出,但是您可以在GitHub上浏览它。 请注意,但是您应该使其可序列化,因为HttpSession中存储的任何数据都可能会被应用程序服务器序列化/反序列化。

还要注意,我也已经将Logout功能实现到LoginServlet类中。 您只需传递“注销”查询参数,它将被检测到并从会话中删除登录令牌。 这样做时,请确保使HttpSession本身无效,只是为了保证安全。 我还公开了一个静态帮助器getOptionalLoginSessiongetOptionalLoginSession在少数几个类之间使用,以检查用户是否已登录。

这几个类很简单,但是在如何管理Session数据上展示了Servlet过滤器和Servlet的用法。 这种编程模式允许用户通过应用程序拥有自己的浏览会话和隐私。

如果要在GlassFish服务器中运行我的servlet3-example ,则可以使用here中列出的任何用户登录。

翻译自: https://www.javacodegeeks.com/2015/01/ee-servlet-3-developing-user-login-with-session-and-filter.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/361071.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ajax应用查询员工信息

首先要用上一篇的步骤启动服务器&#xff0c;建立站点。然后在该站点下创建php文件和html文件。 php代码如下&#xff0c;文件名为server.php <?php //设置页面内容是html编码格式是utf-8 header("Content-Type: text/plain;charsetutf-8"); //header("Co…

局域网基础知识

一、局域网的特征&#xff1a;   局域网分布范围小&#xff0c;投资少&#xff0c;配置简单等&#xff0c;具有如下特征&#xff1a;     1&#xff0e;传输速率高&#xff1a;一般为1Mbps--20Mbps&#xff0c;光纤高速网可达100Mbps&#xff0c;1000MbpS     2&…

初始化懒惰关系以及何时使用它们的5种方法

实体之间关系的延迟加载是JPA中公认的最佳实践。 它的主要目标是仅从数据库中检索请求的实体&#xff0c;并仅在需要时加载相关实体。 如果我们只需要请求的实体&#xff0c;那是一个很好的方法。 但是&#xff0c;如果我们还需要一些相关实体&#xff0c;它会增加工作量&#…

fieldset ----- 不常用的HTML标签

fieldset 元素可将表单内的相关元素分组。 <fieldset> 标签将表单内容的一部分打包&#xff0c;生成一组相关表单的字段。 当一组表单元素放到 <fieldset> 标签内时&#xff0c;浏览器会以特殊方式来显示它们&#xff0c;它们可能有特殊的边界、3D 效果&#xff…

谷歌移动应用强调设计元素:向极简风格转型

导语&#xff1a;美国科技博客TechCrunch今天撰文称&#xff0c;一向不看重设计的谷歌&#xff0c;最近也开始在移动应用中强调设计元素&#xff0c;并向极简风格转型。 以下为文章全文&#xff1a; 谷歌的设计向来不够酷&#xff0c;Gmail和Google Docs的功能都很不错&#xf…

Java 8流和Lambda表达式–解析文件示例

最近&#xff0c;我想从输出日志中提取某些数据。 这是日志文件的一部分&#xff1a; 2015-01-06 11:33:03 b.s.d.task [INFO] Emitting: eVentToRequestsBolt __ack_ack [-6722594615019711369 -1335723027906100557] 2015-01-06 11:33:03 c.s.p.d.PackagesProvider [INFO] -…

使用入站适配器公开HTTP Restful API。 第1部分(XML)

1.简介 这篇文章的目的是使用Spring Integration HTTP入站适配器实现HTTP Restful API。 本教程分为两个部分&#xff1a; XML配置示例&#xff08;同一篇文章&#xff09;。 Java DSL示例。 这将在本教程的下一部分中进行说明&#xff0c;展示如何使用Spring Integration Ja…

根据thickbox定制自己的遮罩层

Jquery有很多遮罩层插件&#xff0c;我使用了一款叫做thickbox的插件&#xff0c;效果很好。 但现在我要和后台交互&#xff0c;后台处理数据时间较长&#xff0c;为了提示用户&#xff0c;同时不让用户进行其他操作&#xff0c;这时候thickbox就不适用了&#xff0c;因为它允许…

Es6学习笔记(7)----数组的扩展

参考书《ECMAScript 6入门》http://es6.ruanyifeng.com/数组的扩展1.扩展运算符:可以将数组转化成逗号隔离的单个参数...[1,2,3] //控制台运行报错console.log(...[1,2,3]);//1,2,3(1)代替apply方法function test(a,b){return a b;}test.apply(null,[1,2]) 同 test(...[1,2]) 作…

使用jOOQ和JavaFX将SQL数据转换为图表

最近&#xff0c;我们已经展示了Java 8和函数式编程将如何为使用jOOQ和Java 8 lambda和Streams进行SQL数据的函数数据转换为Java开发人员带来新的视角。 今天&#xff0c;我们将这一步骤更进一步&#xff0c;将数据转换为JavaFX XYChart.Series以根据数据生成美观的条形图。 设…

有一只猪400斤,桥承重200斤,怎么过桥?

条件:1 猪是活猪,任何方案都不 能切割猪。2 故事发生在猪王国&#xff0c;不要引 入人的因素。3 是过桥&#xff0c;不是过河&#xff0c;不要 说游泳过去。4 是过桥&#xff0c;不是过涧&#xff0c;不要 说飞过去。5 桥是承重200斤的桥&#xff0c;把桥 挪到平地上抑或过另一…

node.js学习笔记(1)

一&#xff0e; 安装以及环境配置 安装路径 http://nodejs.cn/download/ 多种环境选择 环境变量的配置 Step1 先检查环境变量中的系统变量里面的path,查看是否加入了node.js 例如我的node.js安装路径是C:\Program Files\nodejs 那么&#xff0c;这个path里面就应该加…

do语句转化为局部函数一例

do: (do ((x a (b x)) (y c (d y))) ((test x y) (z x y)) (f x y)) 局部函数&#xff1a; (labels ((rec (x y) (cond ((test x y) (z x y)) (t (f x y) (rec (b x) (d y)))))) …

主要版本发布后Java开发人员应使用的15种工具

新部署的生存工具包&#xff1a;适用于Java开发人员的工具&#xff0c;这些工具经常将代码部署到生产中&#xff01; Takipi会检测生产中的所有错误&#xff0c;并像发生错误时一样显示变量值 立即部署并获得免费的T恤 适用于新部署的终极生存套件 与在僵尸末日场景下玩弄&…

js dom node.children与node.childNodes区别

不同点&#xff1a;node.children不会取到节点下面的TextNode但是node.childNodes会取到 共同点&#xff1a;两者都是集合类数组&#xff0c;可以通过索引的方式取到值也可以用for循环遍历 更多专业前端知识&#xff0c;请上 【猿2048】www.mk2048.com

Java EE 7批处理和魔兽世界–第2部分

今天&#xff0c;我将把第二部分带到我以前关于Java EE 7批处理和《魔兽世界–第1部分》的帖子中。 在本文中&#xff0c;我们将了解如何从第1部分中获得的数据中汇总和提取指标。 概括 批处理目的是下载魔兽世界拍卖行的数据&#xff0c;处理拍卖并提取指标。 这些指标将建立…

js导航条 二级滑动 模仿块级作用域

for(var i 1;i<7;i){    //因为首级标题有6个&#xff0c;对每个首级标题添加mouseover和mouseout事件。    //这里用到块级作用域(function(k){document.getElementById("p_"k).addEventListener(mouseover,function(event){document.getElementById(p_…

js 中的console.log有什么作用

主要是方便你调式javascript用的。你可以看到你在页面中输出的内容。 相比alert他的优点是&#xff1a; 他能看到结构话的东西&#xff0c;如果是alert&#xff0c;淡出一个对象就是[object object],但是console能看到对象的内容。console不会打断你页面的操作&#xff0c;如…

太糟糕了,Java 8没有Iterable.stream()

这是最近比较有趣的Stack Overflow问题之一&#xff1a; 为什么Iterable不提供stream&#xff08;&#xff09;和parallelStream&#xff08;&#xff09;方法&#xff1f; 最初&#xff0c;直接将Iterable转换为Stream似乎很直观&#xff0c;因为在90&#xff05;的用例中&a…

struts+swfupload实现批量图片上传(上):swfupload

custom_settings : {progressTarget : "fsUploadProgress",cancelButtonId : "btnCancel",uploadButtonId : "btnUpload",myFileListTarget : "idFileList" },custom_settings调用方法 this.customSettings.cancelButtonId 缩略图js …