Spring 安全的基础知识 [英] Basics of Spring Security

查看:34
本文介绍了Spring 安全的基础知识的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Spring Security 的基础知识是什么,即 Spring 如何在内部设置安全性.为 Spring Security 提供开箱即用的所有 bean 有哪些?

What are the very basics of Spring Security i.e. how Spring sets up security internally. What are all the beans involved that are to be provided for Spring Security to work out-of-the-box?

推荐答案

我将首先解释如何将 Spring Security 引入到您的应用程序中.

I shall start first by explaining, how to bring in Spring Security into your application.

只需将以下依赖项添加到您的应用程序中即可.现在,当您运行应用程序时,默认情况下会实现 spring 安全性.(截至 2021 年 4 月,未来版本可能会发生变化)

Just add below dependency to your application. Now, when you run your application the spring security is implemented by default. (As of April 2021, version might change in future)

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-core</artifactId>
    <version>5.4.5</version>
</dependency>

仔细查看控制台,您将看到为默认用户生成的密码:user.密码是您需要使用的哈希值.

Closely looking at the console, you will see a password generated for default user: user. The password is a hash that you need to use.

当您现在从您的应用程序访问任何 URL 时,您将受到 Postman 的限制.从您的浏览器中,您将看到一个登录页面,您需要在其中输入此用户名和密码,然后才能访问您的 URL.这样就设置了内置的 Spring Security.

When you access any URL from your application now, you will be restricted from Postman. From your browser, you will see a login page where you need to enter this username and password and you will be through to your URL. That sets up the inbuilt Spring Security.

但是幕后发生了什么?

我将通过提醒您 Spring 中的 Servlets and Filters 和 DispatcherServlet 来回答.

I shall answer it by reminding you of Servlets and Filters and DispatcherServlet in Spring.

DispatcherServlet 是 Spring MVC 的基础,它将请求转发到您的控制器.基本上,DispatcherServlet 也是一个 servlet.

DispatcherServlet is the very basic of Spring MVC and it forwards the requests to your controllers. Basically, DispatcherServlet is also a servlet.

我可以在 DispatcherServlet 之前创建一个过滤器链,并在转发请求以命中我的 DispatcherServlet 和控制器之前检查我的身份验证和授权请求.这样,我可以为我的应用程序引入安全性.这正是 Spring Security 所做的.

I can create a chain of filters before DispatcherServlet and check my request for Authentication and Authorization before forwarding the request to hit my DispatcherServlet and then my controllers. This way, I can bring in Security to my application. This is exactly what the Spring Security does.

下面的链接非常巧妙地突出了 DispatcherServlet 之前存在的所有过滤器以及这些过滤器的重要性.请参考以下链接:

The below link very delicately highlights all the filters that are there before DispatcherServlet and what is the importance of those Filters. Please refer the link below:

Spring 安全过滤器链的工作原理

现在,我们需要了解什么是身份验证和授权:

Now, we need to understand what authentication and authorization is:

  1. 身份验证 - 使用您的应用程序的任何人都需要了解一些信息,您需要验证该用户的用户名和密码,以允许他访问您的应用程序.如果他的用户名或密码错误,则表示他未通过身份验证.
  2. 授权 - 一旦用户通过身份验证,您的应用程序的某些 URL 可能只应允许管理员用户访问,而不允许普通用户访问.这称为根据用户的角色授权用户访问您应用的某些部分.

让我们看看过滤链中一些重要的Spring过滤器:

Let us look at some important Spring’s Filter in Filter Chain:

• BasicAuthenticationFilter: 尝试在请求中查找基本身份验证 HTTP 标头,如果找到,则尝试使用标头的用户名和密码对用户进行身份验证.

• BasicAuthenticationFilter: Tries to find a Basic Auth HTTP Header on the request and if found, tries to authenticate the user with the header’s username and password.

• UsernamePasswordAuthenticationFilter: 尝试查找用户名/密码请求参数/POST 正文,如果找到,则尝试使用这些值对用户进行身份验证.

• UsernamePasswordAuthenticationFilter: Tries to find a username/password request parameter/POST body and if found, tries to authenticate the user with those values.

• DefaultLoginPageGeneratingFilter: 为您生成登录页面,如果您没有明确禁用该功能.此过滤器是启用 Spring Security 时获得默认登录页面的原因.

• DefaultLoginPageGeneratingFilter: Generates a login page for you, if you don’t explicitly disable that feature. THIS filter is why you get a default login page when enabling Spring Security.

• DefaultLogoutPageGeneratingFilter:如果您没有明确禁用该功能,则会为您生成一个注销页面.

• DefaultLogoutPageGeneratingFilter: Generates a logout page for you, if you don’t explicitly disable that feature.

• FilterSecurityInterceptor:是否授权.

默认情况下,这些过滤器会为您提供您在浏览器上看到的登录页面.此外,它们还提供注销页面、使用基本身份验证或表单登录登录的功能,以及防止 CSRF 攻击.

These filters, by default, are providing you a login page which you saw on your browser. Also, they provide a logout page, ability to login with Basic Auth or Form Logins, as well as protecting against CSRF attacks.

请记住,在将 Spring Security 添加到 pom.xml 后开始的登录页面.这是由于以下课程而发生的:

Remember, the login page at the beginning just after adding Spring Security to your pom.xml. That is happening because of the below class:

public abstract class WebSecurityConfigurerAdapter implements
                WebSecurityConfigurer<WebSecurity> {

    protected void configure(HttpSecurity http) throws Exception {
            http
                .authorizeRequests()
                    .anyRequest().authenticated()
                    .and()
                .formLogin().and()
                .httpBasic();
        }
}

这个 WebSecurityConfigurerAdapter 类是我们扩展的类,我们覆盖了它的 configure 方法.如上所述,所有请求都需要通过表单登录方法进行基本身份验证.这个登录页面是我们访问 URL 时看到的 Spring 提供的默认页面.

This WebSecurityConfigurerAdapter class is what we extend and we override its configure method. As per above, all the requests need to do basic authentication via form login method. This login page is the default provided by Spring that we saw when we accessed our URL.

现在,下一个问题来了,如果我们想自己做这个配置怎么办?以下主题正好讨论了这一点:

Now, next question arises, what if we want to do this configuration ourselves? The below topic discusses exactly that:

如何配置 Spring Security?

要配置 Spring Security,我们需要有一个 @Configuration、@EnableWebSecurity 类来扩展 WebSecurityConfigurerAdapter 类.

To configure Spring Security, we need to have a @Configuration, @EnableWebSecurity class which extends WebSecurityConfigurerAdapter class.

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

  @Override
  protected void configure(HttpSecurity http) throws Exception {
      http
        .authorizeRequests()
          .antMatchers("/", "/home").permitAll()
          .anyRequest().authenticated()
          .and()
       .formLogin()
         .loginPage("/login")
         .permitAll()
         .and()
      .logout()
        .permitAll()
        .and()
      .httpBasic();
  }
}

您必须执行上述配置.现在,您可以进行特定的安全配置,即允许所有 URL、哪些需要进行身份验证、应用程序将执行的身份验证类型以及特定 URL 上允许的角色是什么.

You must do above the mentioned configurations. Now, you can do your specific security configuration i.e. which all URLs are allowed, which need to be authenticated, what are the types of authentication the application will perform and what are the roles that are allowed on specific URLs.

所以,基本上,你所有的认证和授权信息都在这里配置了.其他关于 CORS、CSRF 和其他漏洞的配置也在这里完成,但这超出了基础的范围.

So, basically, all your authentication and authorization information is configured here. Other configuration regarding CORS, CSRF and other exploits is also done here, but that is out of the scope of the basics.

在上面的示例中,任何用户都可以访问 //home 的所有请求,即任何人都可以访问它们并获得响应,但其他请求需要认证.此外,我们还允许表单登录,即当访问除 //home 之外的任何请求时,用户将看到一个登录页面,他将在其中输入他的用户名和密码,该用户名/密码将使用基本身份验证进行身份验证,即发送 HTTP 基本身份验证标头进行身份验证.

In the example above, all requests going to / and /home are allowed to any user i.e. anyone can access them and get response but the other requests need to be authenticated. Also, we have allowed form login i.e. when any request apart from / and /home is accessed, the user will be presented with a login page where he will input his username and password and that username/password will be authenticated using basic authentication i.e. sending in an HTTP Basic Auth Header to authenticate.

到目前为止,我们已经添加了 Spring Security,保护了我​​们的 URL,配置了 Spring Security.但是,我们将如何检查要进行身份验证的用户名和密码?下面讨论这个:

Till now, we have added Spring Security, protected our URLs, configured Spring Security. But, how will we check the username and password to be authenticated? The below discusses this:

您需要指定一些@Beans 才能使 Spring Security 工作.为什么需要一些豆类?因为 Spring Container 需要这些 bean 来实现底层的安全性.

You need to specify some @Beans to get Spring Security working. Why some beans are needed? Because Spring Container needs these beans to implement security under the hood.

你需要提供这两个 bean - UserDetailsS​​ervice &密码编码器.

You need to provide these two beans – UserDetailsService & PasswordEncoder.

UserDetailsS​​ervice 这负责将您的用户提供给 Spring 容器.用户可以出现在您的数据库、内存中或任何地方.例如:它可以与用户名、密码、角色等列存储在用户表中.

UserDetailsService This is responsible for providing your user to the Spring container. The user can be present either in your DB, memory, anywhere. Ex: It can be stored in User table with username, password, roles and other columns.

@Bean
public UserDetailsService userDetailsService() {
    return new MyUserDetailsService();
}

上面,我们提供了我们的自定义 MyUserDetailsS​​ervice,它必须是 Spring 容器的 UserDetailsS​​ervice 子项,以识别其用途.以下是示例实现:

Above, we are providing our custom MyUserDetailsService which has to be a UserDetailsService child for Spring container to identify its purpose. Below is the sample implementation:

public class MyDatabaseUserDetailsService implements UserDetailsService {

        UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { 
         //  Load the user from the users table by username. If not found, throw UsernameNotFoundException.
         // Convert/wrap the user to a UserDetails object and return it.
        return someUserDetails;
    }
}

public interface UserDetails extends Serializable {

    String getUsername();

    String getPassword();

    // isAccountNonExpired,isAccountNonLocked,
    // isCredentialsNonExpired,isEnabled
}

你看,UserDetailsS​​ervice 应该为容器提供 UserDetails 对象.

You see, UserDetailsService shall provide the container with UserDetails object.

默认情况下,Spring 提供了 UserDetailsS​​ervice 的这些实现:

By default, Spring provides these implementations of UserDetailsService:

1.JdbcUserDetailsManager- 这是一个基于 JDBC 的 UserDetailsS​​ervice.您可以对其进行配置以匹配您的用户表/列结构.

1. JdbcUserDetailsManager- which is a JDBC based UserDetailsService. You can configure it to match your user table/column structure.

2.InMemoryUserDetailsManager- 将所有用户详细信息保存在内存中.这通常用于测试目的.

2. InMemoryUserDetailsManager- which keeps all userdetails in memory. This is generally used for testing purposes.

3.org.springframework.security.core.userdetail.User– 这是自定义应用程序中最常用的.您可以在您的用户对象的自定义实现上扩展这个 User 类.

3. org.springframework.security.core.userdetail.User– This is what is used mostly in custom applications. You can extend this User class on your custom implementation for your user object.

现在,如上所述,如果有任何请求到达并需要进行身份验证,那么由于我们有 UserDetailsS​​ervice,我们将从 UserDetailsS​​ervice 返回的 UserDetails 对象中为发送请求的用户获取用户,并可以对其进行身份验证使用从我们的 UserDetailsS​​ervice 收到的用户名/密码发送.

Now, as per above if any request arrives and needs to be authenticated, then since we have UserDetailsService in place, we will get the user from the UserDetails object returned by UserDetailsService for the user who has sent the request and can authenticate his sent username/password with the one received from our UserDetailsService.

这样,用户就通过了身份验证.

This way, the user is authenticated.

注意:从用户那里收到的密码会自动散列.因此,如果我们的 UserDetailsS​​ervice 没有密码的哈希表示,即使密码正确也会失败.

Note: The password received from user is automatically hashed. So, if we do not have the hash representation of password from our UserDetailsService, it will fail even when the password is correct.

为了防止这种情况,我们向容器提供了 PasswordEncoder bean,它将对 UserDetails 对象中的密码应用 PasswordEncoder 指定的散列算法并为其生成散列.然后,它会检查散列的密码并验证或失败用户.

To prevent this, we provide PasswordEncoder bean to our container which will apply the hashing algorithm specified by the PasswordEncoder on the password in UserDetails object and make a hash for it. Then, it checks both the hashed passwords and authenticates or fails a user.

PasswordEncoder- 出于安全目的,它会提供您密码的哈希值.为什么?您不能/不应该处理普通密码.这违背了 Spring Security 的初衷.更好的是,用任何算法散列它.

PasswordEncoder- This provides a hash of your password for security purposes. Why? You cannot/should not deal with plain passwords. That beats the very purpose of Spring Security. Better, hash it with any algorithm.

@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
    return new BCryptPasswordEncoder();
}

现在,您可以在应用程序的任何位置自动装配这个 PasswordEncoder.

Now, you can autowire this PasswordEncoder anywhere in your application.

AuthenticationProvider-

在某些情况下,我们无法访问用户的密码,但其他一些第三方会以某种奇特的方式存储我们的用户信息.

In some cases, we do not have access to the user’s password but some other third party stores our user's information in some fancy way.

在这些情况下,我们需要为 Spring 容器提供 AuthenticationProvider bean.一旦容器拥有此对象,它将尝试使用我们提供的实现进行身份验证,以向该第三方进行身份验证,该第三方将为我们提供一个 UserDetails 对象或我们可以从中获取 UserDetails 对象的任何其他对象.

In those cases, we need to provide AuthenticationProvider beans to our Spring container. Once container has this object, it will try to authenticate with the implementation we have provided to authenticate with that third party which will give us a UserDetails object or any other object from which we can obtain our UserDetails object.

一旦获得,这意味着我们通过了身份验证,我们将发回包含我们的用户名、密码和权限/角色的 UsernamePasswordAuthenticationToken.如果没有获得,我们可以抛出异常.

Once, this is obtained, that means we are authenticated and we will send back a UsernamePasswordAuthenticationToken with our username, password and authorities/roles. If it is not obtained, we can throw an exception.

    @Bean
    public AuthenticationProvider authenticationProvider() {
        return new MyAuthenticationProvider();
    }

AuthenticationProvider 主要由一种方法组成,基本实现可能如下所示:

An AuthenticationProvider consists primarily of one method and a basic implementation could look like this:

public class MyAuthenticationProvider implements AuthenticationProvider {

        Authentication authenticate(Authentication authentication)  
                throws AuthenticationException {
            String username = authentication.getPrincipal().toString(); 
            String password = authentication.getCredentials().toString();

            User user = callThirdPartyService(username, password); 
            if (user == null) {                                     
                throw new AuthenticationException("Incorrect username/password");
            }
            return new UserNamePasswordAuthenticationToken(user.getUsername(), user.getPassword(), user.getAuthorities());
        }
}

这就是 Spring Security 基础知识或底层功能以及我们如何利用这些来定制我们的安全实现的全部内容.您可以在任何地方找到示例.更高级的主题,如 JWT、Oauth2 实现、CSRF 预防、CORS 限额等超出了范围.

Thats all there is to Spring Security basics or under the hood functionality and how we can leverage these to customize our security implementation. You can find examples anywhere. More advanced topics such as JWT, Oauth2 implementation, CSRF prevention, CORS allowance are beyond the scope.

这篇关于Spring 安全的基础知识的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆