# 4.3.2 创建用户登录页面

默认的登录页面比你开始时使用的笨拙的 HTTP 基本对话框要好得多，但它仍然相当简单，不太适合 Taco Cloud 应用程序的其余部分。

要替换内置的登录页面，首先需要告诉 Spring Security 自定义登录页面的路径。这可以通过调用传递给 configure() 的 HttpSecurity 对象上的 formLogin() 来实现：

```java
@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
            .antMatchers("/design", "/orders")
                .access("hasRole('ROLE_USER')")
            .antMatchers(“/”, "/**").access("permitAll")
        
        .and()
            .formLogin()
            .loginPage("/login");
}
```

请注意，在调用 formLogin() 之前，需要使用对 and() 的调用来连接这一部分的配置和前面的部分。and() 方法表示已经完成了授权配置，并准备应用一些额外的 HTTP 配置。在开始新的配置部分时，将多次使用 and()。

连接之后，调用 formLogin() 开始配置自定义登录表单。之后对 loginPage() 的调用指定了将提供自定义登录页面的路径。当 Spring Security 确定用户未经身份验证并且需要登录时，它将把用户重定向到此路径。

现在需要提供一个控制器来处理该路径上的请求。因为你的登录页面非常简单 —— 除了一个视图什么都没有 —— 在 WebConfig 中声明它为一个视图控制器是很容易的。下面的 addViewControllers() 方法在将 “/” 映射到主控制器的视图控制器旁边设置登录页面视图控制器：

```java
@Override
public void addViewControllers(ViewControllerRegistry registry) {
    registry.addViewController("/").setViewName("home");
    registry.addViewController("/login");
}
```

最后，需要定义 login 页面视图本身，因为使用 Thymeleaf 作为模板引擎，下面的 Thymeleaf 模板应该做得很好：

```markup
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">
    <head>
        <title>Taco Cloud</title>
    </head>
    
    <body>
        <h1>Login</h1>
        <img th:src="@{/images/TacoCloud.png}"/>
        
        <div th:if="${error}">
            Unable to login. Check your username and password.
        </div>
        
        <p>New here? Click<a th:href="@{/register}">here</a> to register.</p>
        <!-- tag::thAction[] -->
        <form method="POST" th:action="@{/login}" id="loginForm">
        <!-- end::thAction[] -->
            <label for="username">Username: </label>
            <input type="text" name="username" id="username" /><br/>
            
            <label for="password">Password: </label>
            <input type="password" name="password" id="password" /><br/>
            
            <input type="submit" value="Login"/>
        </form>
    </body>
</html>
```

关于这个登录页面需要注意的关键事情是，它发布到的路径以及用户名和密码字段的名称。默认情况下，Spring Security 在 /login 监听登录请求，并期望用户名和密码字段命名为 username 和 password。但是，这是可配置的。例如，以下配置自定义路径和字段名：

```java
.and()
    .formLogin()
        .loginPage("/login")
        .loginProcessingUrl("/authenticate")
        .usernameParameter("user")
        .passwordParameter("pwd")
```

这里，指定 Spring Security 应该监听请求 /authenticate 请求以处理登录提交。此外，用户名和密码字段现在应该命名为 user 和 pwd。

默认情况下，当 Spring Security 确定用户需要登录时，成功的登录将直接将用户带到他们所导航到的页面。如果用户要直接导航到登录页面，成功的登录将把他们带到根路径（例如，主页）。但你可以通过指定一个默认的成功页面来改变：

```java
.and()
    .formLogin()
        .loginPage("/login")
        .defaultSuccessUrl("/design")
```

按照这里的配置，如果用户在直接进入登录页面后成功登录，那么他们将被引导到 /design 页面。

另外，可以强制用户在登录后进入设计页面，即使他们在登录之前已经在其他地方导航，方法是将 true 作为第二个参数传递给 defaultSuccessUrl：

```java
.and()
    .formLogin()
        .loginPage("/login")
        .defaultSuccessUrl("/design", true)
```

现在已经处理了自定义登录页面，让我们来看看身份验证的另一面 —— 如何让用户登出。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://potoyang.gitbook.io/spring-in-action-v5/di-4-zhang-spring-an-quan/4.3-bao-hu-web-qing-qiu/4.3.2-chuang-jian-yong-hu-deng-lu-ye-mian.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
