Spring 4 Security MVC登录注销示例
今天,我们将学习Spring Security登录示例。
Spring Security登录注销示例
在本文中,我们将开发Spring 4 MVC Security Web应用程序,以通过使用In-Memory选项提供登录和注销功能。
这个例子使用带有Spring Annotations的Spring Java Config,这意味着不使用web.xml和Spring XML Configuration(旧样式)。
如果您不熟悉Spring 3.x Security Module,请先阅读以下文章以品尝Spring Security Recipe。
- 使用内存,UserDetailsService和JDBC身份验证的Spring MVC安全性示例
- Servlet Web Application中的Spring Security使用DAO,JDBC,内存中身份验证
Spring 4 Security Module支持以下选项来存储和管理用户凭证:
- 内存中存储
- 关系数据库(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 Security Feature开发一个Login和Logout逻辑。
该应用程序的主要目的是在不使用" web.xml"并且不编写任何一行Spring XML Beans Configuration的情况下开发应用程序。
这意味着我们将使用带有Spring Annotations的Spring Java Config功能。
我们将使用以下功能开发此应用程序:
- 欢迎页面
- 登录页面
- 主页
- 登出功能
请使用以下步骤来开发和探索此Spring 4 Security简单登录示例。
- 在Spring STS Suite中使用以下详细信息创建" Simple 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.theitroad</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注释开发Login Controller。
LoginController.java
package com.theitroad.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 theitroad 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.theitroad.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("theitroad") .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 Annotation用于在基于Spring MVC的Web应用程序中启用Web安全。
注意:-@EnableWebSecurity = @EnableWebMVCSecurity +其他功能。
这就是在Spring 4.x Framework中不推荐使用@EnableWebMVCSecurity Annotation的原因。
" LoginSecurityConfig"类或者指定用于配置Spring Security的任何类应扩展" WebSecurityConfigurerAdapter"类或者实现相关接口。
configureGlobal()方法用于存储和管理用户凭证。
在configureGlobal()方法中,我们可以使用Authority()方法来定义应用程序角色,例如" ROLE_USER"。
我们也可以出于相同目的使用role()方法。Authoritys()和Roles()方法之间的区别:authorities()需要完整的角色名称,例如" ROLE_USER"
Roles()需要一个角色名称,例如" USER"。
它将自动为该" USER"角色名称添加" ROLE_"值。
注意:-我们将在接下来的帖子中开发另一个示例来演示诸如" USER"," ADMIN"之类的角色。
被配置(HttpSecurity http)下面的代码片段用于避免未经授权访问"/homePage"。
如果您尝试直接访问此页面,我们将自动重定向到"/loginPage"页面。
.antMatchers("/homePage").access("hasRole('ROLE_USER')")
如果我们删除了access(" hasRole('ROLE_USER')")方法调用,那么我们无需登录应用程序即可访问此页面。
我们已经使用formLogin()和logout()方法配置了登录和注销功能。
启用Spring MVC配置
LoginApplicationConfig.java
package com.theitroad.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.theitroad.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 Framework中启用Spring Web MVC应用程序功能
@Import Annotation用于将Spring Security Configuration类导入该类。
@ComponentScan Annotation用于在指定的程序包中进行组件扫描。
它等于Spring XML Configuration中的" <context:component-scan>"。初始化Spring Security
package com.theitroad.spring.secuity.config.core; import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer; public class SpringSecurityInitializer extends AbstractSecurityWebApplicationInitializer { }
" SpringSecurityInitializer"用于注册" DelegatingFilterProxy"以使用springSecurityFilterChain。
它避免了在web.xml文件中编写过滤器配置。
- 初始化Spring MVC应用程序
" SpringMVCWebAppInitializer"类用于在基于注释的配置中在没有web.xml文件的情况下初始化" DispatcherServlet"。
SpringMVCWebAppInitializer.java
package com.theitroad.spring.secuity.config.core; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; import com.theitroad.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 theitroad 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>theitroad 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 theitroad 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 Application,我们需要任何支持带有Servlet 3.1.0容器的Spring 4和Java 8环境的Web容器。
在Spring STS Suite中的Spring TC Server上部署和运行
它会自动访问我们的应用程序欢迎页面网址,如下所示。
单击"登录到theitroad"链接以访问登录页面。
现在,提供错误的登录详细信息,然后单击"登录"按钮。
其中我们可以观察到以下错误消息:"提供的凭据无效。
"
- 现在,提供在" LoginSecurityConfig"类中配置的正确登录详细信息。
成功登录我们的应用程序后,我们可以看到带有"注销"链接的应用程序主页。
- 单击"注销"链接以从应用程序注销。
其中我们可以观察到我们已成功退出应用程序,并再次重定向到"登录"页面。
我们可以在此登录页面中看到一些注销成功的消息。
注意:-如果我们观察此示例,则说明我们没有正确使用web.xml文件。
由于是Web应用程序,因此Maven会搜索web.xml文件,如果在应用程序中找不到该文件,则会引发一些错误。
为了避免与Maven相关的问题,我们需要在pom.xml文件中配置" <failOnMissingWebXml>"标志。