Spring 4 Security MVC 登录注销示例
今天我们将学习Spring Security 登录示例。在阅读本文之前,请先阅读我之前的文章“Spring 4 Security 简介”,以了解一些基础知识。
Spring Security 登录注销示例
在本文中,我们将开发Spring 4 MVC 安全Web 应用程序,以使用内存选项提供登录和注销功能。此示例使用带有 Spring 注释的 Spring Java Config,这意味着无需使用 web.xml 和 Spring XML 配置(旧式)。如果您不熟悉 Spring 3.x 安全模块,请先阅读以下文章以了解 Spring Security Recipe。
- 使用内存、UserDetailsService 和 JDBC 身份验证的 Spring MVC 安全示例
- Servlet Web 应用程序中使用 DAO、JDBC、内存身份验证的 Spring Security
Spring 4 安全模块支持以下选项来存储和管理用户凭证:
- 内存存储
- 关系数据库 (RDBMS)
- 无 SQL 数据存储
- LDAP
我们将在此示例中使用“内存存储”选项。我们将在后续文章中讨论其他选项。我们将使用 Spring 4.0.2.RELEASE、Spring STS 3.7 Suite IDE、带有 Java 1.8 的 Spring TC Server 3.1 和 Maven 构建工具来开发此示例。
Spring Security 登录示例
我们将使用 Spring 4 安全功能开发登录和注销逻辑。此应用程序的主要目的是开发一个不使用“web.xml”且无需编写一行 Spring XML Beans 配置的应用程序。这意味着我们将使用 Spring Java Config 功能和 Spring Annotations。我们将使用以下功能开发此应用程序:
- 欢迎页面
- 登录页面
- 主页
- 注销功能
请使用以下步骤开发和探索此 Spring 4 Security 简单登录示例。
- 在 Spring STS Suite 中创建一个“简单的 Spring Web Maven”项目,详细信息如下
Project Name : SpringMVCSecruityMavenApp
- 使用以下内容更新 pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="https://maven.apache.org/POM/4.0.0"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>com.journaldev</groupId>
<artifactId>SpringMVCSecruityMavenApp</artifactId>
<packaging>war</packaging>
<version>1.0</version>
<properties>
<java.version>1.8</java.version>
<spring.version>4.0.2.RELEASE</spring.version>
<spring.security.version>4.0.2.RELEASE</spring.security.version>
<servlet.api.version>3.1.0</servlet.api.version>
<jsp.api.version>2.2</jsp.api.version>
<jstl.version>1.2</jstl.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${servlet.api.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>${jsp.api.version}</version>
</dependency>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>${jstl.version}</version>
</dependency>
</dependencies>
<build>
<finalName>SpringMVCSecruityMavenApp</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
</project>
注意:-如果您不了解“<failOnMissingWebXml>”标志,请阅读本文末尾以更好地了解此元素的用法。- 首先,使用 Spring 的@Controller注释 开发登录控制器。LoginController.java
package com.journaldev.spring.web.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class LoginController {
@RequestMapping(value = { "/"}, method = RequestMethod.GET)
public ModelAndView welcomePage() {
ModelAndView model = new ModelAndView();
model.setViewName("welcomePage");
return model;
}
@RequestMapping(value = { "/homePage"}, method = RequestMethod.GET)
public ModelAndView homePage() {
ModelAndView model = new ModelAndView();
model.setViewName("homePage");
return model;
}
@RequestMapping(value = "/loginPage", method = RequestMethod.GET)
public ModelAndView loginPage(@RequestParam(value = "error",required = false) String error,
@RequestParam(value = "logout", required = false) String logout) {
ModelAndView model = new ModelAndView();
if (error != null) {
model.addObject("error", "Invalid Credentials provided.");
}
if (logout != null) {
model.addObject("message", "Logged out from JournalDEV successfully.");
}
model.setViewName("loginPage");
return model;
}
}
代码说明:-我们在“LoginController”中定义了三种方法来处理三种不同类型的客户端请求
- welcomePage() 将处理所有使用“/”URI 的客户端请求。
- homePage() 将处理所有使用“/homePage”URI 的客户端请求。
- loginPage() 将处理所有使用“/loginPage”URI 的客户端请求。
- 在 loginPage() 中,我们负责处理错误和注销消息。
- 然后开发一个类“LoginSecurityConfig” ,使用 Spring 4 Security API 提供登录和注销安全功能。LoginSecurityConfig.java
package com.journaldev.spring.secuity.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
@EnableWebSecurity
public class LoginSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder authenticationMgr) throws Exception {
authenticationMgr.inMemoryAuthentication()
.withUser("journaldev")
.password("jd@123")
.authorities("ROLE_USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/homePage").access("hasRole('ROLE_USER')")
.and()
.formLogin().loginPage("/loginPage")
.defaultSuccessUrl("/homePage")
.failureUrl("/loginPage?error")
.usernameParameter("username").passwordParameter("password")
.and()
.logout().logoutSuccessUrl("/loginPage?logout");
}
}
代码说明:-我们在“LoginSecurityConfig”中定义了两种方法来存储和管理用户凭证并处理登录和注销安全功能。
- @EnableWebSecurity注释用于在任何 Web 应用程序中启用 Web 安全。
- @EnableWebMVCSecurity注释用于在基于 Spring MVC 的 Web 应用程序中启用 Web 安全性。 注意:- @EnableWebSecurity = @EnableWebMVCSecurity + 额外功能。这就是@EnableWebMVCSecurity注释在 Spring 4.x Framework.4 中被弃用的原因。“LoginSecurityConfig”类或任何指定用于配置 Spring Security 的类都应扩展“WebSecurityConfigurerAdapter”类或实现相关接口。
- configureGlobal() 方法用于存储和管理用户凭证。
- 在 configureGlobal() 方法中,我们可以使用 authority() 方法来定义我们的应用程序角色,如“ROLE_USER”。我们也可以使用 role() 方法来达到同样的目的。
- rights() 和 role() 方法之间的区别:
- authority() 需要一个完整的角色名称,如“ROLE_USER”roles() 需要一个角色名称,如“USER”。它将自动将“ROLE_”值添加到此“USER”角色名称。注意:-我们将在我的后续文章中开发另一个示例来演示“USER”、“ADMIN”等角色。
- 处理登录和注销安全的重要方法是配置(HttpSecurity http)
- 以下代码片段用于避免未经授权访问“/homePage”。如果您尝试直接访问此页面,我们将自动重定向到“/loginPage”页面。
.antMatchers("/homePage").access("hasRole('ROLE_USER')")
如果我们删除access(“hasRole('ROLE_USER')”)方法调用,那么我们无需登录应用程序即可访问此页面。13. 我们已经使用 formLogin() 和 logout() 方法配置了登录和注销功能。
- 启用 Spring MVC 配置 LoginApplicationConfig.java
package com.journaldev.spring.secuity.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;
@EnableWebMvc
@Configuration
@ComponentScan({ "com.journaldev.spring.*" })
@Import(value = { LoginSecurityConfig.class })
public class LoginApplicationConfig {
@Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}
代码解释:-我们使用“LoginApplicationConfig”类来定义 Spring MVC 视图解析器,以避免编写“web.xml”文件。
- @EnableWebMvc注释用于在 Spring 框架中启用 Spring Web MVC 应用程序功能
- @Import注解用于将 Spring Security 配置类导入到此类中。
- @ComponentScan注解用于在指定包中进行组件扫描。它相当于Spring XML 配置中的“ context:component-scan ”。
- 初始化 Spring Security
package com.journaldev.spring.secuity.config.core;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
public class SpringSecurityInitializer extends AbstractSecurityWebApplicationInitializer {
}
“SpringSecurityInitializer” 用于注册以使用 springSecurityFilterChain。它避免在 web.xml 文件中编写过滤器配置。-DelegatingFilterProxy
初始化 Spring MVC 应用程序“SpringMVCWebAppInitializer”类用于在基于注释的配置中初始化“DispatcherServlet”,而无需 web.xml 文件。SpringMVCWebAppInitializer.java
package com.journaldev.spring.secuity.config.core;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
import com.journaldev.spring.secuity.config.LoginApplicationConfig;
public class SpringMVCWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { LoginApplicationConfig.class };
}
@Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
笔记:-
- 当我们访问应用程序时,默认情况下,SpringMVCWebAppInitializer 的 getServletMappings() 将允许访问根 URL:“/”。我们可以重写以转发到不同的 URL。
- Spring 或 Pivotal 团队正在解决这个问题,通过引入注释来避免编写过多的 Java 代码。请查看https://jira.spring.io/browse/SPR-10359。
- 开发welcomePage.jsp文件
<h3>Welcome to JournalDEV Tutorials</h3>
<a href="${pageContext.request.contextPath}/loginPage">Login to Journal</a>
- 开发loginPage.jsp文件
<%@ taglib prefix="c" uri="https://java.sun.com/jsp/jstl/core"%>
<html>
<body onload='document.loginForm.username.focus();'>
<h3>JournalDEV Tutorials</h3>
<c:if test="${not empty error}"><div>${error}</div></c:if>
<c:if test="${not empty message}"><div>${message}</div></c:if>
<form name='login' action="<c:url value='/loginPage' />" method='POST'>
<table>
<tr>
<td>UserName:</td>
<td><input type='text' name='username' value=''></td>
</tr>
<tr>
<td>Password:</td>
<td><input type='password' name='password' /></td>
</tr>
<tr>
<td colspan='2'><input name="submit" type="submit" value="submit" /></td>
</tr>
</table>
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
</form>
</body>
</html>
- 开发homepage.jsp文件
<%@taglib prefix="c" uri="https://java.sun.com/jsp/jstl/core"%>
<h3>Welcome to JournalDEV Tutorials</h3>
<ul>
<li>Java 8 tutorial</li>
<li>Spring tutorial</li>
<li>Gradle tutorial</li>
<li>BigData tutorial</li>
</ul>
<c:url value="/logout" var="logoutUrl" />
<form id="logout" action="${logoutUrl}" method="post" >
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
</form>
<c:if test="${pageContext.request.userPrincipal.name != null}">
<a href="javascript:document.getElementById('logout').submit()">Logout</a>
</c:if>
- 最终的项目结构如下:
运行 Spring Security MVC 登录注销示例
要运行这个 Spring Web 应用程序,我们需要任何支持 Spring 4 和 Java 8 环境以及 Servlet 3.1.0 容器的 Web 容器。
- 在 Spring STS Suite 中的 Spring TC Server 上部署并运行
- 它自动访问我们的应用程序欢迎页面网址,如下所示。 - 单击“登录 JournalDEV”链接访问登录页面。 - 现在,提供错误的登录详细信息并单击“登录”按钮。 在这里我们可以看到这个错误消息:“提供的凭据无效。” - 现在,提供在“LoginSecurityConfig”类中配置的正确的登录详细信息。 成功登录我们的应用程序后,我们可以通过“注销”链接看到我们的应用程序主页。 - 单击“注销”链接从应用程序中注销。 在这里我们可以观察到我们已成功从应用程序中注销并再次重定向到登录页面。我们可以在此登录页面中看到一些注销成功消息。
注意:-如果我们观察此示例,则我们没有正确使用 web.xml 文件。由于它是一个 Web 应用程序,因此 Maven 会搜索 web.xml 文件,如果在应用程序中找不到,则会引发一些错误。为了避免与 Maven 相关的问题,我们需要在 pom.xml 文件中配置“<failOnMissingWebXml>”标志。这就是有关 Spring 4 安全模块简单示例的全部内容。我们将在我即将发布的文章中开发一些更实时有用的示例,例如管理角色、记住我功能、WebSocket 安全等。如果您喜欢我的帖子或有任何问题/建议,请给我留言。