www.baeldung.com/spring-secu…javascript
做者:Eugen Paraschivhtml
转载自公众号:stackgc前端
在本文中,咱们将介绍如何使用 Spring MVC 实现一个简单的登陆页面,该应用在后端使用了 Spring Security 进行身份验证。java
首先定义一个很是简单的登陆页面:git
<html>
<head></head>
<body>
<h1>Login</h1>
<form name='f' action="login" method='POST'>
<table>
<tr>
<td>User:</td>
<td><input type='text' name='username' value=''></td>
</tr>
<tr>
<td>Password:</td>
<td><input type='password' name='password' /></td>
</tr>
<tr>
<td><input name="submit" type="submit" value="submit" /></td>
</tr>
</table>
</form>
</body>
</html>
复制代码
接下来添加客户端检查,以确保在提交表单以前用户名和密码不为空。针对这个例子,咱们将使用简单的 Javascript,也许 JQuery 是一个更好的选择:github
<script type="text/javascript"> function validate() { if (document.f.username.value == "" && document.f.password.value == "") { alert("Username and password are required"); document.f.username.focus(); return false; } if (document.f.username.value == "") { alert("Username is required"); document.f.username.focus(); return false; } if (document.f.password.value == "") { alert("Password is required"); document.f.password.focus(); return false; } } </script>
复制代码
能够看到,咱们只需检查用户名或密码字段是否为空,若是为空,将弹出一个 javascript 弹窗以显示相应的消息。spring
接下来,将消息本地化应用到前端。有如下消息类型,每一个都以不一样的方式进行本地化:后端
在这两种状况下,咱们须要为要支持的每种语言建立一个 message.properties 文件。文件名称应遵以下约定:messages_[localeCode].properties。api
好比,若是要支持英语和西班牙语,咱们须要新建这两个文件:messages_en.properties 和 messages_es_ES.properties。请注意,对于英文,命名为 messages.properties 也是能够。安全
咱们将把这两个文件放在项目的 classpath 中(src/main/resources)。这些文件只包含须要用到的不一样语言的错误代码和消息,例如:
message.username=Username required
message.password=Password required
message.unauth=Unauthorized access!!
message.badCredentials=Invalid username or password
message.sessionExpired=Session timed out
message.logoutError=Sorry, error login out
message.logoutSucc=You logged out successfully
复制代码
Spring MVC 提供了一个 LocaleResolver,它与 LocaleChangeInterceptor API 一块儿使用,可根据区域(locale)设置显示不一样语言的消息。要配置本地化,咱们须要在 MVC 配置中定义如下 bean:
@Override
public void addInterceptors(InterceptorRegistry registry) {
LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
localeChangeInterceptor.setParamName("lang");
registry.addInterceptor(localeChangeInterceptor);
}
@Bean
public LocaleResolver localeResolver() {
CookieLocaleResolver cookieLocaleResolver = new CookieLocaleResolver();
return cookieLocaleResolver;
}
@Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource =
new ReloadableResourceBundleMessageSource();
messageSource.setBasename("classpath:messages");
messageSource.setUseCodeAsDefaultMessage(true);
messageSource.setDefaultEncoding("UTF-8");
messageSource.setCacheSeconds(0);
return messageSource;
}
复制代码
这里有一个重要和更高级的注意事项:咱们须要确保 messageSource bean 定义在正确的 Spring 上下文中 — 它将在此上下文中使用。请记住,Web 应用具备根上下文,而且有一个(或多个)servlet 上下文。
默认状况下,locale 解析器(resolver)将从 HTTP 头获取区域代码。要强制使用默认语言环境,咱们须要设置 localeResolver():
@Bean
public LocaleResolver localeResolver() {
CookieLocaleResolver cookieLocaleResolver = new CookieLocaleResolver();
cookieLocaleResolver.setDefaultLocale(Locale.ENGLISH);
return cookieLocaleResolver;
}
复制代码
该 locale 解析器是一个 CookieLocaleResolver,这意味着它将客户端 cookie 中的 locale 信息存储起来,在每次登陆时以及整个访问过程当中记住用户的 locale 设置。
此外,还有一个 SessionLocaleResolver,能够存储整个会话中的 locale 设置。要使用此 LocaleResolver,咱们须要使用如下方法替换上述方法:
@Bean
public LocaleResolver localeResolver() {
SessionLocaleResolver sessionLocaleResolver = new SessionLocaleResolver();
return sessionLocaleResolver;
}
复制代码
最后,请注意,LocaleChangeInterceptor 将根据经过登陆页面的简单连接发送的 lang 参数的值来更改语言环境:
<a href="?lang=en">English</a> |
<a href="?lang=es_ES">Spanish</a>
复制代码
JSP/JSTL API 将用于在 jsp 页上获取本地化消息。要使用 jsp 本地化库,需将如下依赖项添加到 pom.xml 中:
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.2-b01</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
复制代码
为了启用 JSP/JSTL 支持并在 login.jsp 中显示本地化消息,须要在页面中更改:
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
复制代码
<fmt:setBundle basename="messages" />
复制代码
<fmt:message key="message.password" var="noPass" />
<fmt:message key="message.username" var="noUser" />
复制代码
<script type="text/javascript"> function validate() { if (document.f.username.value == "" && document.f.password.value == "") { alert("${noUser} and ${noPass}"); document.f.username.focus(); return false; } if (document.f.username.value == "") { alert("${noUser}"); document.f.username.focus(); return false; } if (document.f.password.value == "") { alert("${noPass}"); document.f.password.focus(); return false; } } </script>
复制代码
若是以前的操做发生失败,将传递一个错误参数到登陆页面。例如,注册表单提交按钮将加载登陆页面。若是注册成功,则在登陆表单中显示成功消息,若是失败,则会出现错误消息。
在下面的登陆表单示例中,咱们经过拦截 regSucc 和 regError 参数来实现,并根据它们的值显示本地化消息。
<c:if test="${param.regSucc == true}">
<div id="status">
<spring:message code="message.regSucc">
</spring:message>
</div>
</c:if>
<c:if test="${param.regError == true}">
<div id="error">
<spring:message code="message.regError">
</spring:message>
</div>
</c:if>
复制代码
若是因为某些缘由形成登陆失败,Spring Security 将会重定向到显示登陆错误页面的 URL,咱们将其指定为 /login.html?error=true。
所以,相似于如何在页面中显示注册状态的问题,咱们须要在登陆发生问题的状况下作一样的处理:
<c:if test="${param.error != null}">
<div id="error">
<spring:message code="message.badCredentials">
</spring:message>
</div>
</c:if>
复制代码
请注意,咱们使用了 spring:message... 标签。这意味着在 Spring MVC 处理期间将生成错误消息。
你能够在 github 项目中找到完整的登陆页面(包括了 js 验证和附加的状态消息)的示例代码。
在下面的示例中,logout.html 页面中的 jsp 代码 <c:if test="${not empty SPRING_SECURITY_LAST_EXCEPTION}"> 将检查注销过程当中是否有存在错误。
例如,若是自定义注销 handler 在重定向到注销页面以前尝试存储用户数据时发生了持久化异常。虽然这些错误很罕见,但咱们也应该尽可能处理。
让咱们来看看完整的 logout.jsp:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="sec"
uri="http://www.springframework.org/security/tags"%>
<%@taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<c:if test="${not empty SPRING_SECURITY_LAST_EXCEPTION}">
<div id="error">
<spring:message code="message.logoutError">
</spring:message>
</div>
</c:if>
<c:if test="${param.logSucc == true}">
<div id="success">
<spring:message code="message.logoutSucc">
</spring:message>
</div>
</c:if>
<html>
<head>
<title>Logged Out</title>
</head>
<body>
<a href="login.html">Login</a>
</body>
</html>
复制代码
请注意,注销页面还读取查询字符串参数 logSucc,若是其值等于 true,则显示本地化成功消息。
本文的重点是前端的登陆过程,而不是后端。
<form-login.../> 指令将应用引导处处理登陆错误 URL:
authentication-failure-url="/login.html?error=true"
复制代码
<logout invalidate-session="false" logout-success-url="/logout.html?logSucc=true" delete-cookies="JSESSIONID" />
复制代码
logout-success-url 属性简单地重定向到注销页面,该参数肯定注销成功。
在本文中,咱们介绍了如何为 Spring Security 支持的应用实现 Login 页面以及处理登陆验证、显示身份验证错误和消息本地化。