Spring Security Form Login – Spring安全表格登录

最后修改: 2013年 5月 1日

中文/混合/英文(键盘快捷键:t)

1. Introduction

1.介绍

This tutorial will focus on Login with Spring Security. We’re going to build on top of the previous Spring MVC example, as that’s a necessary part of setting up the web application along with the login mechanism.

本教程将重点介绍使用Spring Security进行登录。我们将在之前的 Spring MVC 示例的基础上展开,因为这是设置 Web 应用程序以及登录机制的必要部分。

2. The Maven Dependencies

2.Maven的依赖性

When working with Spring Boot, the spring-boot-starter-security starter will automatically include all dependencies, such as spring-security-core, spring-security-web, and spring-security-config among others:

在使用Spring Boot时,spring-boot-starter-security启动器将自动包括所有依赖项,如spring-security-corespring-security-webspring-security-config等。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
    <version>2.3.3.RELEASE</version>
</dependency>

If we don’t use Spring Boot, please see the Spring Security with Maven article, which describes how to add all required dependencies. Both standard spring-security-web and spring-security-config will be required.

如果我们不使用Spring Boot,请参见Spring Security with Maven文章,其中介绍了如何添加所有必要的依赖项。标准的spring-security-webspring-security-config都将是必需的。

3. Spring Security Java Configuration

3.Spring Security Java配置

Let’s start by creating a Spring Security configuration class that creates a SecurityFilterChain bean.

让我们先创建一个Spring Security配置类,创建一个SecurityFilterChain Bean.

By adding @EnableWebSecurity, we get Spring Security and MVC integration support:

通过添加@EnableWebSecurity,我们得到了Spring Security和MVC集成支持。

@Configuration
@EnableWebSecurity
public class SecSecurityConfig {

    @Bean
    public InMemoryUserDetailsManager userDetailsService() {
        // InMemoryUserDetailsManager (see below)
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        // http builder configurations for authorize requests and form login (see below)
    }
}

In this example, we used in-memory authentication and defined three users.

在这个例子中,我们使用了内存认证并定义了三个用户。

Next we’ll go through the elements we used to create the form login configuration.

接下来我们将浏览一下我们用来创建表单登录配置的元素。

Let’s start by building our Authentication Manager.

让我们从建立我们的认证管理器开始。

3.1. InMemoryUserDetailsManager

3.1.InMemoryUserDetailsManager

The Authentication Provider is backed by a simple, in-memory implementation, InMemoryUserDetailsManager. This is useful for rapid prototyping when a full persistence mechanism is not yet necessary:

认证提供者由一个简单的、内存中的实现支持,InMemoryUserDetailsManager。当还不需要完整的持久化机制时,这对快速原型设计很有用。

    @Bean
    public InMemoryUserDetailsManager userDetailsService() {
        UserDetails user1 = User.withUsername("user1")
            .password(passwordEncoder().encode("user1Pass"))
            .roles("USER")
            .build();
        UserDetails user2 = User.withUsername("user2")
            .password(passwordEncoder().encode("user2Pass"))
            .roles("USER")
            .build();
        UserDetails admin = User.withUsername("admin")
            .password(passwordEncoder().encode("adminPass"))
            .roles("ADMIN")
            .build();
        return new InMemoryUserDetailsManager(user1, user2, admin);
    }

Here we’ll configure three users with the username, password, and role hard-coded.

在这里,我们将配置三个用户,其用户名、密码和角色是硬编码的。

Starting with Spring 5, we also have to define a password encoder. In our example, we’ll use the BCryptPasswordEncoder:

从Spring 5开始,我们还必须定义一个密码编码器。在我们的例子中,我们将使用BCryptPasswordEncoder:

@Bean 
public PasswordEncoder passwordEncoder() { 
    return new BCryptPasswordEncoder(); 
}

Next let’s configure the HttpSecurity.

接下来让我们配置一下HttpSecurity.

3.2. Configuration to Authorize Requests

3.2.授权请求的配置

We’ll start by doing the necessary configurations to Authorize Requests.

我们将首先对授权请求进行必要的配置。

Here we’re allowing anonymous access on /login so that users can authenticate. We’ll restrict /admin to ADMIN roles and securing everything else:

在这里,我们在/login上允许匿名访问,以便用户可以进行身份验证。我们将限制/adminADMIN角色的访问,并确保其他一切的安全。

   @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.csrf()
            .disable()
            .authorizeRequests()
            .antMatchers("/admin/**")
            .hasRole("ADMIN")
            .antMatchers("/anonymous*")
            .anonymous()
            .antMatchers("/login*")
            .permitAll()
            .anyRequest()
            .authenticated()
            .and()
            // ...
    }

Note that the order of the antMatchers() elements is significant; the more specific rules need to come first, followed by the more general ones.

请注意,antMatchers()元素的顺序是重要的;更具体的规则需要放在前面,然后是更一般的规则

3.3. Configuration for Form Login

3.3.表格登录的配置

Next we’ll extend the above configuration for form login and logout:

接下来,我们将为表单登录和注销扩展上述配置。

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
      // ...
      .and()
      .formLogin()
      .loginPage("/login.html")
      .loginProcessingUrl("/perform_login")
      .defaultSuccessUrl("/homepage.html", true)
      .failureUrl("/login.html?error=true")
      .failureHandler(authenticationFailureHandler())
      .and()
      .logout()
      .logoutUrl("/perform_logout")
      .deleteCookies("JSESSIONID")
      .logoutSuccessHandler(logoutSuccessHandler());
      return http.build();
}
  • loginPage() – the custom login page
  • loginProcessingUrl() – the URL to submit the username and password to
  • defaultSuccessUrl() – the landing page after a successful login
  • failureUrl() – the landing page after an unsuccessful login
  • logoutUrl() – the custom logout

4. Add Spring Security to the Web Application

4.将Spring安全添加到Web应用中

To use the above-defined Spring Security configuration, we need to attach it to the web application.

为了使用上述定义的Spring Security配置,我们需要将其附加到Web应用程序中。

We’ll use the WebApplicationInitializer, so we don’t need to provide any web.xml:

我们将使用WebApplicationInitializer,所以我们不需要提供任何web.xml:

public class AppInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext sc) {

        AnnotationConfigWebApplicationContext root = new AnnotationConfigWebApplicationContext();
        root.register(SecSecurityConfig.class);

        sc.addListener(new ContextLoaderListener(root));

        sc.addFilter("securityFilter", new DelegatingFilterProxy("springSecurityFilterChain"))
          .addMappingForUrlPatterns(null, false, "/*");
    }
}

Note that this initializer isn’t necessary if we’re using a Spring Boot application. For more details on how the security configuration is loaded in Spring Boot, have a look at our article on Spring Boot security auto-configuration.

注意,如果我们使用的是Spring Boot应用程序,则不需要这个初始化器。有关如何在Spring Boot中加载安全配置的更多细节,请看我们关于Spring Boot安全自动配置的文章

5. The Spring Security XML Configuration

5.Spring Security的XML配置

Let’s also have a look at the corresponding XML configuration.

我们也来看看相应的XML配置。

The overall project is using Java configuration, so we need to import the XML configuration file via a Java @Configuration class:

整个项目使用的是Java配置,所以我们需要通过Java @Configuration类导入XML配置文件。

@Configuration
@ImportResource({ "classpath:webSecurityConfig.xml" })
public class SecSecurityConfig {
   public SecSecurityConfig() {
      super();
   }
}

And the Spring Security XML Configuration, webSecurityConfig.xml:

还有Spring Security的XML配置,webSecurityConfig.xml

<http use-expressions="true">
    <intercept-url pattern="/login*" access="isAnonymous()" />
    <intercept-url pattern="/**" access="isAuthenticated()"/>

    <form-login login-page='/login.html' 
      default-target-url="/homepage.html" 
      authentication-failure-url="/login.html?error=true" />
    <logout logout-success-url="/login.html" />
</http>

<authentication-manager>
    <authentication-provider>
        <user-service>
            <user name="user1" password="user1Pass" authorities="ROLE_USER" />
        </user-service>
        <password-encoder ref="encoder" />
    </authentication-provider>
</authentication-manager>

<beans:bean id="encoder" 
  class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
</beans:bean>

6. The web.xml

6、web.xml

Before the introduction of Spring 4, we used to configure Spring Security in the web.xml; only an additional filter added to the standard Spring MVC web.xml:

在引入Spring 4之前,我们曾经在web.xml中配置Spring Security;只是在标准的Spring MVC web.xml中添加一个额外的过滤器。

<display-name>Spring Secured Application</display-name>

<!-- Spring MVC -->
<!-- ... -->

<!-- Spring Security -->
<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

The filter – DelegatingFilterProxy – simply delegates to a Spring-managed bean – the FilterChainProxy – which itself is able to benefit from full Spring bean life-cycle management and such.

过滤器–DelegatingFilterProxy–简单地委托给一个Spring管理的Bean–FilterChainProxy–它本身能够受益于完整的Spring Bean生命周期管理等。

7. The Login Form

7.登录表格

The login form page is going to be registered with Spring MVC using the straightforward mechanism to map views names to URLs. Furthermore, there is no need for an explicit controller in between:

登录表单页面将使用直接的机制在Spring MVC中注册,以映射视图名称到URL。此外,这中间不需要一个明确的控制器。

registry.addViewController("/login.html");

This, of course, corresponds to the login.jsp:

当然,这与login.jsp相对应。

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

The Spring Login form has the following relevant artifacts:

Spring登录表单有以下相关工件。

  • login – the URL where the form is POSTed to trigger the authentication process
  • username – the username
  • password – the password

8. Further Configuring Spring Login

8.进一步配置Spring登录

We briefly discussed a few configurations of the login mechanism when we introduced the Spring Security Configuration above. Now let’s go into some greater detail.

在上面介绍Spring安全配置的时候,我们简要地讨论了登录机制的一些配置。现在让我们深入了解一些细节。

One reason to override most of the defaults in Spring Security is to hide that the application is secured with Spring Security. We also want to minimize the information a potential attacker knows about the application.

覆盖 Spring Security 中大多数默认值的一个原因是,隐藏应用程序是由 Spring Security 保护的。我们还希望尽量减少潜在攻击者对应用程序的了解。

Fully configured, the login element looks like this:

完全配置后,登录元素看起来像这样。

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http.formLogin()
      .loginPage("/login.html")
      .loginProcessingUrl("/perform_login")
      .defaultSuccessUrl("/homepage.html",true)
      .failureUrl("/login.html?error=true")
    return http.build();
}

Or the corresponding XML configuration:

或相应的XML配置。

<form-login 
  login-page='/login.html' 
  login-processing-url="/perform_login" 
  default-target-url="/homepage.html"
  authentication-failure-url="/login.html?error=true" 
  always-use-default-target="true"/>

8.1. The Login Page

8.1.登录页面

Next we’ll configure a custom login page using the loginPage() method:

接下来,我们将使用loginPage()方法配置一个自定义登录页面:

http.formLogin()
  .loginPage("/login.html")

Similarly, we can use the XML configuration:

同样地,我们可以使用XML配置。

login-page='/login.html'

If we don’t specify this, Spring Security will generate a very basic Login Form at the /login URL.

如果我们不指定这一点,Spring Security将在/login URL上生成一个非常基本的登录表单。

8.2. The POST URL for Login

8.2.登录的POST URL

The default URL where the Spring Login will POST to trigger the authentication process is /login, which used to be /j_spring_security_check before Spring Security 4.

Spring Login将POST以触发认证过程的默认URL是/login,,在Spring Security 4之前,它曾经是/j_spring_security_check

We can use the loginProcessingUrl method to override this URL:

我们可以使用loginProcessingUrl方法来重写这个URL。

http.formLogin()
  .loginProcessingUrl("/perform_login")

We can also use the XML configuration:

我们也可以使用XML配置。

login-processing-url="/perform_login"

By overriding this default URL, we’re concealing that the application is actually secured with Spring Security. This information should not be available externally.

通过覆盖这个默认的URL,我们掩盖了应用程序实际上是由Spring Security保护的。这个信息不应该从外部获得。

8.3. The Landing Page on Success

8.3.关于成功的着陆页

After successfully logging in, we will be redirected to a page that by default is the root of the web application.

成功登录后,我们将被重定向到一个页面,该页面默认为Web应用程序的根。

We can override this via the defaultSuccessUrl() method:

我们可以通过defaultSuccessUrl()方法来重写这个。

http.formLogin()
  .defaultSuccessUrl("/homepage.html")

Or with XML configuration:

或者用XML配置。

default-target-url="/homepage.html"

If the always-use-default-target attribute is set to true, then the user is always redirected to this page. If that attribute is set to false, then the user will be redirected to the previous page they wanted to visit before being prompted to authenticate.

如果always-use-default-target属性被设置为true,那么用户总是被重定向到这个页面。如果该属性被设置为false,那么用户将被重定向到他们在被提示验证之前想要访问的前一个页面。

8.4. The Landing Page on Failure

8.4.失败的着陆页

Similar to the Login Page, the Login Failure Page is autogenerated by Spring Security at /login?error by default.

与登录页面类似,登录失败页面由Spring Security默认在/login?error处自动生成。

To override this, we can use the failureUrl() method:

要覆盖这一点,我们可以使用failureUrl()方法。

http.formLogin()
  .failureUrl("/login.html?error=true")

Or with XML:

或者用XML。

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

9. Conclusion

9.结论

In this Spring Login Example, we configured a simple authentication process. We also discussed the Spring Security Login Form, the Security Configuration, and some of the more advanced customizations available.

在这个Spring登录实例中,我们配置了一个简单的认证过程。我们还讨论了Spring安全登录表单、安全配置,以及一些更高级的自定义功能。

The implementation of this article can be found in the GitHub project – this is an Eclipse-based project, so it should be easy to import and run as it is.

本文的实现可以在GitHub项目中找到 – 这是一个基于Eclipse的项目,所以应该很容易导入并按原样运行。

When the project runs locally, the sample HTML can be accessed at:

当项目在本地运行时,可以通过以下网址访问样本HTML。

http://localhost:8080/spring-security-mvc-login/login.html