> For the complete documentation index, see [llms.txt](https://potoyang.gitbook.io/spring-in-action-v5/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](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).

# 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)
```

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