原文: https://howtodoinjava.com/spring-security/login-form-based-spring-3-security-example/

学习使用 Spring Security 教程中讨论的详细信息,将 Spring Security 登录表单添加到任何 Spring Web 应用程序。

阅读更多: Spring Security 5 登录表单示例[为 Spring 5 更新]

1. 背景资料

我们学会了在链接的帖子中集成 Spring 3 和 Hibernate 之间。 该应用程序是简单的 Web 应用程序,它提供了一个视图,用户可以在其中添加/编辑员工。

使该应用程序安全。 本教程的范围是:

  • 只有授权用户才能访问编辑员工屏幕。
  • 未经授权的用户应显示登录屏幕。
  • 成功的凭据应转发到编辑员工屏幕。
  • 不成功的凭据应转发到拒绝访问屏幕。
  • 应该有一个注销应用程序的链接。

2. Spring Security Maven 依赖项

让我们从第一步开始,即更新项目依赖项。 由于以下原因,它将在演示中添加以下four sub-modules

  1. spring-security-core:它包含核心身份验证以及访问控制类和接口。
  2. spring-security-web:包含过滤器和相关的 Web 安全基础结构代码。 它还启用了基于 URL 的安全性,我们将在此演示中使用它。
  3. spring-security-config:它包含安全名称空间解析代码。 如果您使用 Spring Security XML 文件进行配置,则需要它。
  4. spring-security-taglibs:它为访问安全信息和在 JSP 中应用安全约束提供基本支持。

pom.xml

  1. <properties>
  2. <org.springframework.version>3.0.5.RELEASE</org.springframework.version>
  3. </properties>
  4. <!-- Spring Security -->
  5. <dependency>
  6. <groupid>org.springframework.security</groupid>
  7. <artifactid>spring-security-core</artifactid>
  8. <version>${org.springframework.version}</version>
  9. <type>jar</type>
  10. <scope>compile</scope>
  11. </dependency>
  12. <dependency>
  13. <groupid>org.springframework.security</groupid>
  14. <artifactid>spring-security-web</artifactid>
  15. <version>${org.springframework.version}</version>
  16. <type>jar</type>
  17. <scope>compile</scope>
  18. </dependency>
  19. <dependency>
  20. <groupid>org.springframework.security</groupid>
  21. <artifactid>spring-security-config</artifactid>
  22. <version>${org.springframework.version}</version>
  23. <type>jar</type>
  24. <scope>compile</scope>
  25. </dependency>
  26. <dependency>
  27. <groupid>org.springframework.security</groupid>
  28. <artifactid>spring-security-taglibs</artifactid>
  29. <version>${org.springframework.version}</version>
  30. <type>jar</type>
  31. <scope>compile</scope>
  32. </dependency>

现在使用“ mvn compile”命令更新项目中的依赖项。

3. 在web.xml中配置DelegatingFilterProxy

Spring Security 的 Web 基础结构完全基于标准 Servlet 过滤器。 这些过滤器在web.xml文件中定义,否则 servlet 容器将忽略它们。

在 Spring Security 中,过滤器类也是在应用程序上下文中定义的 Spring Bean,因此能够利用 Spring 丰富的依赖注入机制和生命周期接口。 Spring 的 DelegatingFilterProxy 提供了web.xml和应用上下文之间的链接。

web.xml

  1. <filter>
  2. <filter-name>springSecurityFilterChain</filter-name>
  3. <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
  4. </filter>
  5. <filter-mapping>
  6. <filter-name>springSecurityFilterChain</filter-name>
  7. <url-pattern>/*</url-pattern>
  8. </filter-mapping>

如果您没有使用任何明确的过滤器定义,并且希望 spring 为您配置基本的基础架构,则如上例所示,将过滤器名称用作“ springSecurityFilterChain”。 请注意,您不应自己使用此 bean 名称。 将其添加到web.xml后,就可以开始编辑 Spring Security 配置文件了。 Web 安全服务是使用元素配置的。

同样不要忘记将安全配置文件放在上下文配置位置设置中。

web.xml

  1. <context-param>
  2. <param-name>contextConfigLocation</param-name>
  3. <param-value>
  4. /WEB-INF/employee-servlet.xml
  5. /WEB-INF/application-security.xml
  6. </param-value>
  7. </context-param>

完整的web.xml文件如下所示:

web.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xmlns="http://java.sun.com/xml/ns/javaee"
  4. xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
  5. xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
  6. id="WebApp_ID" version="2.5">
  7. <display-name>Archetype Created Web Application</display-name>
  8. <welcome-file-list>
  9. <welcome-file>/WEB-INF/index.jsp</welcome-file>
  10. </welcome-file-list>
  11. <filter>
  12. <filter-name>springSecurityFilterChain</filter-name>
  13. <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
  14. </filter>
  15. <filter-mapping>
  16. <filter-name>springSecurityFilterChain</filter-name>
  17. <url-pattern>/*</url-pattern>
  18. </filter-mapping>
  19. <servlet>
  20. <servlet-name>employee</servlet-name>
  21. <servlet-class>
  22. org.springframework.web.servlet.DispatcherServlet
  23. </servlet-class>
  24. <load-on-startup>1</load-on-startup>
  25. </servlet>
  26. <servlet-mapping>
  27. <servlet-name>employee</servlet-name>
  28. <url-pattern>/</url-pattern>
  29. </servlet-mapping>
  30. <context-param>
  31. <param-name>contextConfigLocation</param-name>
  32. <param-value>
  33. /WEB-INF/employee-servlet.xml
  34. /WEB-INF/application-security.xml
  35. </param-value>
  36. </context-param>
  37. <listener>
  38. <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  39. </listener>
  40. </web-app>

4. 配置登录注销安全性

正如我们在上一节中了解到的那样,将过滤器名称用作springSecurityFilterChain可以帮助您使用元素配置基本基础结构。 让我们先看看它是如何配置的? 我已经为这个演示编写了一个基本配置:

application-security.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans:beans xmlns="http://www.springframework.org/schema/security"
  3. xmlns:beans="http://www.springframework.org/schema/beans"
  4. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans
  6. http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  7. http://www.springframework.org/schema/security
  8. http://www.springframework.org/schema/security/spring-security-3.0.3.xsd">
  9. <http auto-config="true" use-expressions="true">
  10. <intercept-url pattern="/login" access="permitAll" />
  11. <intercept-url pattern="/logout" access="permitAll" />
  12. <intercept-url pattern="/accessdenied" access="permitAll" />
  13. <intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
  14. <form-login login-page="/login" default-target-url="/list" authentication-failure-url="/accessdenied" />
  15. <logout logout-success-url="/logout" />
  16. </http>
  17. <authentication-manager alias="authenticationManager">
  18. <authentication-provider>
  19. <user-service>
  20. <user name="lokesh" password="password" authorities="ROLE_USER" />
  21. </user-service>
  22. </authentication-provider>
  23. </authentication-manager>
  24. </beans:beans>

让我们看看这个配置的实际含义。

  • http:包括与配置相关的网址级别安全性。 此元素是所有与 Web 相关的名称空间功能的父级。

  • auto-config:包括一些基本服务。 它是

    1. <http>
    2. <form-login />
    3. <http-basic />
    4. <logout />
    5. </http>


的简写

  • use-expressions:这里使用表达式来保护单个 URL。 这些表达式可以是例如 hasRole([role])hasAnyRole([role1,role2])permitAlldenyAll等。

  • intercept-url:这将匹配请求中请求的网址格式,并根据访问值决定要采取的操作。

  • form-login: 当用户尝试访问任何安全的 URL 时,这将成为图片。 映射到login-page属性的登录页面将用于身份验证检查。 它是 spring security login-processing-url
    如果未提供,spring 将为用户提供内置的登录页面。 如果登录成功或由于无效的用户/密码匹配而导致登录失败,它也包含默认目标的属性。

  • logout:如果在应用程序中调用注销,这将有助于查找下一个视图。

我正在使用基于 XML 的用户服务,即我不会去数据库进行密码验证,而是将用户名/密码组合存储在配置文件本身中。 要使用此设置王,请使用内置的内置用户详细信息服务来设置authentication-manager。 在更实时的应用程序中,这将是一些从远程数据库中获取数据的用户服务。

5. Spring 控制器

我将重用控制器,并将在控制器中添加其他映射和处理器方法。 这些其他 URL 是/login/logout/accessdenied。 具有所有方法处理器的更新后的控制器如下所示:

EditEmployeeController.java

  1. package com.howtodoinjava.controller;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. import org.springframework.stereotype.Controller;
  4. import org.springframework.ui.ModelMap;
  5. import org.springframework.validation.BindingResult;
  6. import org.springframework.web.bind.annotation.ModelAttribute;
  7. import org.springframework.web.bind.annotation.PathVariable;
  8. import org.springframework.web.bind.annotation.RequestMapping;
  9. import org.springframework.web.bind.annotation.RequestMethod;
  10. import com.howtodoinjava.entity.EmployeeEntity;
  11. import com.howtodoinjava.service.EmployeeManager;
  12. @Controller
  13. public class EditEmployeeController {
  14. @Autowired
  15. private EmployeeManager employeeManager;
  16. public void setEmployeeManager(EmployeeManager employeeManager) {
  17. this.employeeManager = employeeManager;
  18. }
  19. @RequestMapping(value = "/login", method = RequestMethod.GET)
  20. public String login(ModelMap model) {
  21. return "login";
  22. }
  23. @RequestMapping(value = "/accessdenied", method = RequestMethod.GET)
  24. public String loginerror(ModelMap model) {
  25. model.addAttribute("error", "true");
  26. return "denied";
  27. }
  28. @RequestMapping(value = "/logout", method = RequestMethod.GET)
  29. public String logout(ModelMap model) {
  30. return "logout";
  31. }
  32. @RequestMapping(value = "/", method = RequestMethod.GET)
  33. public String defaultPage(ModelMap map) {
  34. return "redirect:/list";
  35. }
  36. @RequestMapping(value = "/list", method = RequestMethod.GET)
  37. public String listEmployees(ModelMap map) {
  38. map.addAttribute("employee", new EmployeeEntity());
  39. map.addAttribute("employeeList", employeeManager.getAllEmployees());
  40. return "editEmployeeList";
  41. }
  42. @RequestMapping(value = "/add", method = RequestMethod.POST)
  43. public String addEmployee(
  44. @ModelAttribute(value = "employee") EmployeeEntity employee,
  45. BindingResult result) {
  46. employeeManager.addEmployee(employee);
  47. return "redirect:/list";
  48. }
  49. @RequestMapping("/delete/{employeeId}")
  50. public String deleteEmplyee(@PathVariable("employeeId") Integer employeeId) {
  51. employeeManager.deleteEmployee(employeeId);
  52. return "redirect:/list";
  53. }
  54. }

6. Spring 的视图

现在,我们已经使用安全配置和控制器处理器配置了我们的应用程序。 是时候编写本质上是 JSP 文件的视图了。 jsp 文件中最重要的附加内容是login.jsp文件。

该文件的格式包含用户名和密码字段的文本框。 让我们看看它是怎么写的:

6.1. login.jsp

login.jsp

  1. <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
  2. <%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
  3. <%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>
  4. <html>
  5. <body>
  6. <h1 id="banner">Login to Security Demo</h1>
  7. <form name="f" action="<c:url value='j_spring_security_check'/>"
  8. method="POST">
  9. <table>
  10. <tr>
  11. <td>Username:</td>
  12. <td><input type='text' name='j_username' /></td>
  13. </tr>
  14. <tr>
  15. <td>Password:</td>
  16. <td><input type='password' name='j_password'></td>
  17. </tr>
  18. <tr>
  19. <td colspan="2">&nbsp;</td>
  20. </tr>
  21. <tr>
  22. <td colspan='2'><input name="submit" type="submit">&nbsp;<input name="reset" type="reset"></td>
  23. </tr>
  24. </table>
  25. </form>
  26. </body>
  27. </html>

默认情况下,spring 会自动生成并配置一个UsernamePasswordAuthenticationFilter bean。 默认情况下,此过滤器在处理 Web 表单中的登录 POST 时响应 URL /j_spring_security_check。 用户名字段使用“ j_username”,密码字段使用“ j_password”。

提交此表单时,UsernamePasswordAuthenticationFilter将匹配application-security.xml中身份验证提供程序设置中配置的用户名和密码。

6.2. logout.jsp

logout.jsp

  1. < % session.invalidate(); %>
  2. You are now logged out!!
  3. <a href="//howtodoinjava.com/spring/spring-security/login-form-based-spring-3-security-example/">go back</a>

该视图仅使会话无效,并提供一个链接以返回登录页面。

6.3. denied.jsp

当用户尝试使用无效的用户名和密码组合进行身份验证时,此 jsp 文件将出现在用户屏幕中。 它将在类路径中显示message.properties中配置的相应消息。

denied.jsp

  1. <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
  2. <html>
  3. <body>
  4. <h1 id="banner">Unauthorized Access !!</h1>
  5. <hr />
  6. <c:if test="${not empty error}">
  7. <div style="color:red">
  8. Your fake login attempt was bursted, dare again !!<br />
  9. Caused : ${sessionScope["SPRING_SECURITY_LAST_EXCEPTION"].message}
  10. </div>
  11. </c:if>
  12. <p class="message">Access denied!</p>
  13. <a href="//howtodoinjava.com/spring/spring-security/login-form-based-spring-3-security-example/">Go back to login page</a>
  14. </body>
  15. </html>

7. Spring Security 登录表单演示

是时候测试应用程序了。 只需将应用程序部署在任何服务器中,例如就我而言,我正在使用 Tomcat 7.0. 现在,执行以下步骤:

7.1. 在浏览器http://localhost:8080/Spring3HibernateIntegration中输入 URL

除了/login/logout/accessdeni之外,它将显示登录屏幕,所有其他 URL 都是受保护的 URL。

Spring Security 登录表单示例 - 图1

默认登录界面

7.2. 尝试使用用户名"demo"和密码"1234"进行身份验证

Spring Security 登录表单示例 - 图2

无效的用户名和密码的未经授权访问

由于用户名和密码无效,它将给出拒绝访问错误。

7.3. 尝试使用用户名"lokesh"和密码"password"进行身份验证

Spring Security 登录表单示例 - 图3

成功验证后的员工编辑界面

因为用户名和密码正确,它将显示员工管理屏幕。

7.4. 单击注销链接

Spring Security 登录表单示例 - 图4

注销消息

用户将被注销,并出现登录屏幕。

我希望这个 spring mvc 登录示例能够对使用 xml 配置的基本 Spring Security 机制有所启发。 如果您对此 Spring Security 登录表单示例有任何疑问,请给我评论。

下载源码

学习愉快!