[譯] 學習 Spring Security(二):錯誤處理與本地化

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 本地化

接下來,將消息本地化應用到前端。有如下消息類型,每一個都以不一樣的方式進行本地化:後端

  1. 在 Spring 的控制器或 handler 處理表單以前生成的消息。這些消息能夠在 JSP 頁面中引用,並使用 Jsp/Jstl 進行本地化(參見第 4.3 節)
  2. 一旦頁面已提交給 Spring 進行處理(在提交登陸表單以後)本地化的消息,這些消息將使用 Spring MVC 進行本地化(參見第 4.2 節)

3.一、message.properties 文件

在這兩種狀況下,咱們須要爲要支持的每種語言建立一個 message.properties 文件。文件名稱應遵以下約定:messages_[localeCode].propertiesapi

好比,若是要支持英語和西班牙語,咱們須要新建這兩個文件:messages_en.propertiesmessages_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
複製代碼

3.二、配置 Spring MVC 本地化

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>
複製代碼

3.三、JSP/JSTL 本地化

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>
複製代碼

四、顯示錯誤信息

4.一、登陸驗證錯誤

爲了啓用 JSP/JSTL 支持並在 login.jsp 中顯示本地化消息,須要在頁面中更改:

  1. 將如下 taglib 標籤添加到 login.jsp 中:
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
複製代碼
  1. 添加指向 messages.properties 文件的 jsp/jslt 標籤:
<fmt:setBundle basename="messages" />
複製代碼
  1. 添加如下 fmt:... 標籤以將消息存儲在 jsp 變量中:
<fmt:message key="message.password" var="noPass" />
<fmt:message key="message.username" var="noUser" />
複製代碼
  1. 修改咱們在第 2 節中的登陸驗證腳本,以便本地化錯誤消息:
<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>
複製代碼

4.二、登陸前錯誤

若是以前的操做發生失敗,將傳遞一個錯誤參數到登陸頁面。例如,註冊表單提交按鈕將加載登陸頁面。若是註冊成功,則在登陸表單中顯示成功消息,若是失敗,則會出現錯誤消息。

在下面的登陸表單示例中,咱們經過攔截 regSuccregError 參數來實現,並根據它們的值顯示本地化消息。

<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>
複製代碼

4.三、登陸安全性錯誤

若是因爲某些緣由形成登陸失敗,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 驗證和附加的狀態消息)的示例代碼。

4.四、註銷錯誤

在下面的示例中,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,則顯示本地化成功消息。

五、Spring Security 配置

本文的重點是前端的登陸過程,而不是後端。

5.一、重定向到登陸錯誤 URL

<form-login.../> 指令將應用引導處處理登陸錯誤 URL:

authentication-failure-url="/login.html?error=true"
複製代碼

5.二、註銷成功重定向

<logout invalidate-session="false" logout-success-url="/logout.html?logSucc=true" delete-cookies="JSESSIONID" />
複製代碼

logout-success-url 屬性簡單地重定向到註銷頁面,該參數肯定註銷成功。

六、結論

在本文中,咱們介紹瞭如何爲 Spring Security 支持的應用實現 Login 頁面以及處理登陸驗證、顯示身份驗證錯誤和消息本地化。

相關代碼和連接

相關文章
相關標籤/搜索