Spring Security MVC登录注销示例教程

 

Spring Security MVC登录注销示例教程

 

今天我们将了解Spring Security Login Example。在阅读这篇文章之前,请先阅读我在“Spring 4 Security简介”中的上一篇文章,了解一些基础知识。

Spring Security登录注销示例

Spring安全登录示例,Spring 4安全性MVC登录注销示例,@ EnableWebSecurity,@ EnableWebMVCSecurity注释

在这篇文章中,我们将开发Spring 4 MVC Security Web Application,通过使用In-Memory选项提供登录和注销功能。此示例使用带有Spring Annotations的Spring Java Config,这意味着不使用web.xml和Spring XML Configuration(旧样式)。

如果您不熟悉Spring 3.x安全模块,请首先阅读以下帖子以了解Spring Security Recipe。

  1. 使用内存,UserDetailsS​​ervice和JDBC身份验证的Spring MVC安全示例
  2. 使用DAO,JDBC,内存中身份验证的Servlet Web应用程序中的Spring安全性

Spring 4安全模块支持以下选项来存储和管理用户凭据:

  1. 内存商店
  2. 关系数据库(RDBMS)
  3. 没有SQL数据存储
  4. LDAP

我们将在此示例中使用“In-Memory Store”选项。我们将在以后的帖子中讨论其他选项。

 

 

我们将使用Spring 4.0.2.RELEASE,Spring STS 3.7 Suite IDE,带有Java 1.8的Spring TC Server 3.1和Maven构建工具来开发此示例。

Spring安全登录示例

我们将使用Spring 4安全功能开发登录和注销逻辑。该应用程序的主要目的是在不使用“web.xml”的情况下开发应用程序,而无需编写单行Spring XML Bean配置。这意味着我们将使用Spring Annotations的Spring Java Config功能。

我们将使用以下功能开发此应用程序:

  1. 欢迎页面
  2. 登录页面
  3. 主页
  4. 注销功能

请使用以下步骤开发和探索此Spring 4安全性简单登录示例。


   Project Name : SpringMVCSecruityMavenApp

<?xml version="1.0" encoding="UTF-8"?>
<project
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
   http://maven.apache.org/xsd/maven-4.0.0.xsd"
   xmlns="http://maven.apache.org/POM/4.0.0" 
   xmlns:xsi="http://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>”标志,请阅读本文末尾的内容,以便更好地了解此元素的用法。

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”中定义了三种方法来处理三种不同类型的客户端请求

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”中定义了两个方法来存储和管理用户凭据,并负责登录和注销安全功能。

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 View Resolvers以避免编写“web.xml”文件。


package com.journaldev.spring.secuity.config.core;

import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;

public class SpringSecurityInitializer extends AbstractSecurityWebApplicationInitializer {

}

“SpringSecurityInitializer”用于注册DelegatingFilterProxy使用springSecurityFilterChain。它避免在web.xml文件中编写过滤器配置。

“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[] { "/" };
	}
	
}

注意:-


<h3>Welcome to JournalDEV Tutorials</h3>
<a href="${pageContext.request.contextPath}/loginPage">Login to Journal</a>

<%@ taglib prefix="c" uri="http://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>

<%@taglib prefix="c" uri="http://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登录注销示例

  • 在Spring STS Suite中创建一个“Simple Spring Web Maven”项目,其中包含以下详细信息
  • 使用以下内容更新pom.xml
  • 首先,使用Spring的@Controller注释开发Login Controller。
    1. welcomePage()将处理所有使用“/”URI的客户端请求。
    2. homePage()将处理使用“/ homePage”URI的所有客户端请求。
    3. loginPage()将处理使用“/ loginPage”URI的所有客户端请求。
    4. 在loginPage()中,我们负责处理错误和注销消息。
  • 然后开发一个类“LoginSecurityConfig”,使用Spring 4 Security API提供登录和注销安全功能。

    注意: -
    @EnableWebSecurity = @EnableWebMVCSecurity +额外功能。
    这就是Spring 4.x Framework中不推荐使用@EnableWebMVCSecurity Annotation的原因。

    
    .antMatchers("/homePage").access("hasRole('ROLE_USER')")
    

    如果我们删除访问(“hasRole('ROLE_USER')”)方法调用,那么我们可以访问此页面而无需登录我们的应用程序。

    1. @EnableWebSecurity Annotation用于在任何Web应用程序中启用Web安全性。
    2. @EnableWebMVCSecurity Annotation用于在基于Spring MVC的Web应用程序中启用Web安全性。
    3. “LoginSecurityConfig”类或任何指定用于配置Spring Security的类,应扩展“WebSecurityConfigurerAdapter”类或实现相关接口。
    4. configureGlobal()方法用于存储和管理用户凭据。
    5. 在configureGlobal()方法中,我们可以使用authorities()方法来定义我们的应用程序角色,如“ROLE_USER”。我们也可以将roles()方法用于相同的目的。
    6. authority()和roles()方法之间的区别:
    7. authorities()需要完整的角色名称,如“ROLE_USER” 
      roles()需要角色名称,如“USER”。它会自动将“ROLE_”值添加到此“USER”角色名称。

      注意: -我们将开发另一个示例,在我即将发布的帖子中演示“USER”,“ADMIN”等角色。

       

    8. 配置登录和注销安全的重要方法是配置(HttpSecurity http)
    9. 以下代码剪切用于避免未经授权访问“/ homePage”。如果您尝试直接访问此页面,我们将自动重定向到“/ loginPage”页面。
    10. 我们使用formLogin()和logout()方法配置了登录和注销功能。
  • 启用S​​pring MVC配置
    1. @EnableWebMvc Annotation用于在Spring Framework中启用S​​pring Web MVC应用程序功能
    2. @Import Annotation用于将Spring Security Configuration类导入此类。
    3. @ComponentScan Annotation用于在指定的包中进行组件扫描。它等于Spring XML Configuration中的“<context:component-scan>”。
  • 初始化Spring Security
  • 初始化Spring MVC应用程序
    1. 当我们访问我们的应用程序时,默认情况下SpringMVCWebAppInitializer的getServletMappings()将允许访问根URL:“/”。我们可以覆盖转发到不同的URL。
    2. Spring或Pivotal团队正在通过引入注释来解决这个问题以避免这么多Java代码。请访问https://jira.spring.io/browse/SPR-10359查看此信息。
  • 开发welcomePage.jsp文件
  • 开发loginPage.jsp文件
  • 开发homepage.jsp文件
  • 最终项目结构如下所示:

运行Spring Security MVC登录注销示例

要运行这个Spring Web应用程序,我们需要任何支持Spring 4和带有Servlet 3.1.0 Container的Java 8环境的Web容器。

spring security登录示例

spring 4 mvc安全登录注销示例

spring security登录注销

在这里,我们可以观察到此错误消息:“提供的证书无效。”

spring 4安全登录

成功登录我们的应用程序后,我们可以看到我们的应用程序主页带有“注销”链接。

spring security logout示例

在这里,我们可以看到我们已成功从应用程序中注销,并再次重定向到“登录”页面。

我们可以在此登录页面中观察到一些Logout成功消息。

  • 在Spring STS Suite中部署并运行Spring TC Server
  • 它会自动访问我们的应用程序欢迎页面URL,如下所示。
  • 点击“登录JournalDEV”链接进入登录页面。
  • 现在,提供错误的登录详细信息并单击“登录”按钮。
  • 现在,提供在“LoginSecurityConfig”类中配置的正确登录详细信息。
  • 单击“注销”链接以从应用程序注销。

注意: -
如果我们观察这个例子,我们没有正确使用web.xml文件。由于它是一个Web应用程序,Maven搜索web.xml文件并在应用程序中找不到时会引发一些错误。这是为了避免Maven相关问题,我们需要在pom.xml文件中配置“<failOnMissingWebXml>”标志。

这就是Spring 4 Security Module Simple Example的全部内容。我们将在即将发布的帖子中开发更多实时有用的示例,例如Managing Roles,Rememeber-Me Feature,WebSocket Security等等......

如果您喜欢我的帖子或有任何问题/建议,请给我发表评论。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
一、为什么:要分层 使软件具有结构性,便于开发、维护和管理。 将不同功能模块独立,在需要替换某一模块时不需要改动其他模块,方便代码的复用、替换 二、层与层耦合的概念,利用工厂类解耦 在分层结构中,我们希望将各个功能 约束在各自的模块(层)当中的,而当属于某一层的对象、方法“入侵”到了其他层,如将web层的ServletContext对象传入service层,或service层调用XMLDao独有的方法,就会导致层与层之间的关系过于“紧密”,当需要修改某一层时不可避免的要修改其他关联的层,这和我们软件分层最初的设想-----层与层分离,一个层尽量不依赖其他层存在,当修改一层时无需修改另一层的设想是违背的。这种“入侵”造成的“紧密”关系就早做层与层之间发生的“耦合”,而去掉这种耦合性的过程就叫做层与层之间“解耦” 利用工厂类可以实现解耦的功能 三、如何判断一项功能到底属于哪一层 某一项功能属于哪一层,往往是不能明确确定出来的,这时可以参考如下标准进行判断: 此项功能在业务逻辑上更贴近与哪一层,放在哪一层更能较少耦合 此项功能是否必须使用某一层特有的对象 如果放在哪一层都可以,那么放在哪一层更方便技术上的实现,及方便代码的编写和维护 四、异常的处理 如果一个异常抛给上一层会增加程序的耦合性,请当场解决:如将xml解析错误抛给service层,那么当换成mysqldao时,还需要修改service去掉xml解析异常的处理 如果上一层明确需要此异常进行代码的流转,请抛出:如当查找一个用户信息而用户找不到时,可以抛出一个用户找不到异常,明确要求上一层处理 如果这一层和上一层都能解决尽量在这一层解决掉 如果这一层不能解决,而上一层能解决抛给上一层 如果所有层都不能解决,则应抛出给虚拟机使线程停止,但是如果直接抛出这个异常,则还需要调用者一级一级继续往上抛出最后才能抛给虚拟机,所以还不如在出现异常的位置直接trycatch住后转换为RuntimeException抛出。:如读取配置文件出错,任何层都不能解决,转为RuntimeException抛出,停止线程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值