Spring Web 應用登錄 – 錯誤處理與本地化

Spring MVC,Spring Security
Remote
1
09:32 PM · Nov 29 ,2025

1. 概述在本文中,我們將演示如何使用 Spring MVC 實現一個簡單的登錄頁面,用於處理 Spring Security 在後端進行的身份驗證。

有關如何使用 Spring Security 處理登錄的詳細信息,請參閲本文深入探討配置和實現過程。

2. 登錄頁面讓我們首先定義一個非常簡單的登錄頁面:

<html>
<head></head>
<body>
   <h1>登錄</h1>
   <form name='f' action="login" method='POST'>
      <table>
         <tr>
            <td>用户名:</td>
            <td><input type='text' name='username' value=''></td>
         </tr>
         <tr>
            <td>密碼:</td>
            <td><input type='password' name='password' /></td>
         </tr>
         <tr>
            <td><input name="submit" type="submit" value="提交" /></td>
         </tr>
      </table>
  </form>
</body>
</html>

現在,讓我們包含一個客户端檢查,以確保用户名和密碼在提交表單之前已輸入。對於此示例,我們將使用純 JavaScript,但 jQuery 也是一個不錯的選擇:

<script type="text/javascript">
function validate() {
    if (document.f.username.value == "" && document.f.password.value == "") {
        alert("用户名和密碼不能為空");
        document.f.username.focus();
        return false;
    }
    if (document.f.username.value == "") {
        alert("用户名不能為空");
        document.f.username.focus();
        return false;
    }
    if (document.f.password.value == "") {
        alert("密碼不能為空");
        document.f.password.focus();
        return false;
    }
}
</script>

正如你所看到的,我們只是檢查用户名或密碼字段是否為空;如果為空 – 一個 JavaScript 消息框將彈出,帶有相應的消息。

3. Message Localization

Next – let’s localize the messages we’re using on the front end. There are types of such messages, and each is localized in a different manner:

  1. Messages generated before the form is processed by Spring’s controllers or handlers. These messages ca be referenced in the JSP pages and are localized with Jsp/Jslt localization (see Section 4.3.)
  2. Messages that are localized once a page has been submitted for processing by Spring (after submitting the login form); these messages are localized using Spring MVC localization (See Section 4.2.)

3.1. The message.properties Files

In either case, we need to create a message.properties file for each language we want to support; the names of the files should follow this convention: messages_[localeCode].properties.

For example, if we want to support English and Spanish error messages we would have the file: messages_en.properties and messages_es_ES.properties. Note that, for English – messages.properties is also valid.

We’re going to place these two files in the project’s classpath (src/main/resources). The files simply contain the error codes and messages we need to display in different languages – for example:

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.2. Configuring Spring MVC Localization

Spring MVC provides aLocaleResolver that works in conjunction with itsLocaleChangeInterceptor API to make possible the display of messages in different languages, depending on the locale setting. To configure localization – we need to define the following beans in our MVC configuration:

@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;
}

By default, the locale resolver will obtain the locale code from the HTTP header. To force a default locale, we need to set it on the localeResolver():

@Bean
public LocaleResolver localeResolver() {
    CookieLocaleResolver cookieLocaleResolver = new CookieLocaleResolver();
    cookieLocaleResolver.setDefaultLocale(Locale.ENGLISH);
    return cookieLocaleResolver;
}

This locale resolver is a CookieLocaleResolver which means that it stores the locale information in a client-side cookie; as such – it will remember the user’s locale every time they log in, and during the entire visit.

alternatively, there is aSessionLocaleResolver, which remembers the locale throughout the session. To use this LocaleResolver instead, we need to replace the above method with the following:

@Bean
public LocaleResolver localeResolver() {
    SessionLocaleResolver sessionLocaleResolver = new SessionLocaleResolver();
    return sessionLocaleResolver;
}

Lastly, note that the LocaleChangeInterceptor will change the locale based on the value of a lang parameter sent with the login page by simple links:

<a href="?lang=en">English</a> |
<a href="?lang=es_ES">Spanish</a>

3.3. JSP/JSLT Localization

JSP/JSLT API will be used to display localized messages that are caught in the jsp page itself. To use the jsp localization libraries we should add the following dependencies to the pom.xml:

<dependency>
    <groupId>jakarta.servlet.jsp</groupId>
    <artifactId>jakarta.servlet.jsp-api</artifactId>
    <version>3.1.1</version>
</dependency>
<dependency>
    <groupId>jakarta.servlet</groupId>
    <artifactId>jakarta.servlet-api</artifactId>
    <version>6.0.0</version>
</dependency>

<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>

2. Add the jsp/jslt element that will point to the messages.properties files:

<fmt:setBundle basename="messages" />

3. Add the following fmt:… elements to store the messages on jsp variables:

<fmt:message key="message.password" var="noPass" />
<fmt:message key="message.username" var="noUser" />

4. Modify the login validation script we saw in Section 3 so as to localize the error messages:

<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>

<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>

<c:if test="${param.error != null}"> <div id="error"> <spring:message code="message.badCredentials"> </spring:message> </div> </c:if>

Notice that we are using a <spring:message …> element. This means that the error messages are generated during the Spring MVC processing.

The full login page – including the js validation and these additional status messages can be found in the github project.

<%@ 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>

Notice that the logout page also reads the query string param logSucc, and if its value equal to true, a localized success message will be displayed.

5. Spring Security 配置本文檔的重點是登錄流程的前端,而不是後端——因此我們將僅簡要查看安全配置的主要要點;有關完整的配置,請閲讀上一篇文章。

5.1. 重定向到登錄錯誤 URL在<form-login…/>元素中使用的以下指令將應用程序的流程重定向到處理登錄錯誤的 URL:

authentication-failure-url="/login.html?error=true"

5.2. 成功註銷重定向<logout invalidate-session="false" logout-success-url="/logout.html?logSucc=true" delete-cookies="JSESSIONID" />

logout-success-url屬性僅將應用程序重定向到帶有參數的註銷頁面,以確認註銷成功。

6. 結論

在本文中,我們演示瞭如何為 Spring Security 支持的應用程序實現登錄頁面——處理登錄驗證、顯示身份驗證錯誤和消息本地化。

在下一篇文章中,我們將研究完整的註冊實施——目標是在登錄和註冊過程完全實現,以便為生產環境做好準備。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.