Spring Security Oauth2.0 学习笔记

OAuth2.0 基础

  • 基础流程Spring Security Oauth2.0 学习笔记_第1张图片
  • OAuth2.0授权码模式
    Spring Security Oauth2.0 学习笔记_第2张图片
  • OAuth2.0 简化模式
    Spring Security Oauth2.0 学习笔记_第3张图片
  • OAuth2.0密码模式
    Spring Security Oauth2.0 学习笔记_第4张图片
  • OAuth2.0客户端模式
    Spring Security Oauth2.0 学习笔记_第5张图片
  • 刷新Refresh Token
    Spring Security Oauth2.0 学习笔记_第6张图片

基础说明

  • AbstractSecurityWebApplicationInitializer类:
    • 为应用程序中的每个URL自动注册springSecurityFilterChain过滤器
    • 添加一个ContextLoaderListener来加载WebSecurityConfig。
  • HttpSecurity:
    • WebSecurityConfig只包含关于如何验证用户的信息
    •   protected void configure(HttpSecurity http) throws Exception {
            http
                .authorizeRequests() //authorizerequests()方法有多个子方法,每个匹配器按照声明的顺序进行考虑。
                    .antMatchers("/resources/**", "/signup", "/about").permitAll() //我们指定了任意用户都可以访问的多个URL模式。
                    .antMatchers("/admin/**").hasRole("ADMIN") //任何以“/admin/”开头的URL将被限制为具有“ROLE_ADMIN”角色的用户。
                    .antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')") //任何以“/db/”开头的URL都要求用户同时具有“ROLE_ADMIN”和“ROLE_DBA”。
                    .anyRequest().authenticated() //任何尚未匹配的URL只需要对用户进行身份验证
                    .and()
                .formLogin()
                    .loginPage("/login") //更新的配置指定登录页的位置。
                    .permitAll();        //permitall()方法允许为与基于表单的登录相关联的所有url授予所有用户访问权限。
                .logout() //提供注销的支持。这是在使用WebSecurityConfigurerAdapter时自动应用的。
                    .logoutUrl("/test/logout") //触发注销发生的URL(默认为 /logout)。如果启用了CSRF保护(默认),那么请求也必须是POST。
                    .logoutSuccessUrl("/test/index") //注销后要重定向到的URL。默认是/login?logout。
                    .logoutSuccessHandler(logoutSuccessHandler) //让我们指定一个自定义logoutsuccessesshandler。如果指定了此参数,则忽略logoutSuccessUrl()。
                    .invalidateHttpSession(true)    //指定在注销时是否使HttpSession无效。这在默认情况下是正确的。
                    .addLogoutHandler(logoutHandler) //添加一个LogoutHandler。默认情况下,SecurityContextLogoutHandler被添加为最后一个LogoutHandler。
                    .deleteCookies(cookieNamesToClear) //允许在注销成功时指定要删除的cookie的名称。这是显式添加CookieClearingLogoutHandler的快捷方式。
                    .and()
                    ...
        }
      
    • LogoutHandler:实现表示能够参与注销处理的类。
      • 预期将调用它们来执行必要的清理。因此,它们不应该抛出异常。提供了多种实现:
        • PersistentTokenBasedRememberMeServices
        • TokenBasedRememberMeServices
        • CookieClearingLogoutHandler
        • CsrfLogoutHandler
        • SecurityContextLogoutHandler
    • LogoutSuccessHandler: 注销成功后由LogoutFilter调用
      • 以处理重定向或转发到适当的目的地。注意,该接口几乎与LogoutHandler相同,但可能会引发异常
      • 提供实现:
        • SimpleUrlLogoutSuccessHandler
        • HttpStatusReturningLogoutSuccessHandler
  • 1.注解 @EnableWebSecurity
    • 该注解和 @Configuration 注解一起使用, 注解 WebSecurityConfigurer 类型的类,或者利用@EnableWebSecurity 注解继承 WebSecurityConfigurerAdapter的类,这样就构成了 Spring Security 的配置。
    • @EnableWebSecurity 注解将会启用Web安全功能。
  • 2.抽象类 WebSecurityConfigurerAdapter
    • WebSecurityConfigurerAdapter 提供了一种便利的方式去创建 WebSecurityConfigurer的实例,只需要重写 WebSecurityConfigurerAdapter 的方法,即可配置拦截什么URL、设置什么权限等安全控制。
    • 创建类SecurityConfiguration继承WebSecurityConfigurerAdapter,来对我们应用中所有的安全相关的事项(所有url,验证用户名密码,表单重定向等)进行控制。
    configure(WebSecurity) 通过重载,配置Spring Security的Filter链
    configure(HttpSecurity) 通过重载,配置如何通过拦截器保护请求
    configure(AuthenticationManagerBuilder) 通过重载,配置user-detail服务
  • UserDetailsPasswordService: 自动升级密码存储
  • 3.方法 configure(AuthenticationManagerBuilder auth) 和 **configure(HttpSecurity http) **
  • 4.类 AuthenticationManagerBuilder
    • AuthenticationManagerBuilder 用于创建一个 AuthenticationManager,让我能够轻松的实现内存验证、LADP验证、基于JDBC的验证、添加UserDetailsService、添加AuthenticationProvider。

  • 在不使用Spring引导的情况下使用Spring Security时,首选的方法是利用Spring Security的BOM来确保在整个项目中使用一致的Spring Security版本。
    •   
            
                
                
                    org.springframework.security
                    spring-security-bom
                    5.1.3.RELEASE
                    pom
                    import
                
            
        
      

Oauth2.0 客户端

  • HttpSecurity.oauth2Client() 提供了许多自定义OAuth 2.0客户机的配置选项。
    •   @EnableWebSecurity
        public class OAuth2ClientSecurityConfig extends WebSecurityConfigurerAdapter {
      
            @Override
            protected void configure(HttpSecurity http) throws Exception {
                http
                    .oauth2Client()
                        .clientRegistrationRepository(this.clientRegistrationRepository())
                        .authorizedClientRepository(this.authorizedClientRepository())
                        .authorizedClientService(this.authorizedClientService())
                        .authorizationCodeGrant()
                            .authorizationRequestRepository(this.authorizationRequestRepository())
                            .authorizationRequestResolver(this.authorizationRequestResolver())
                            .accessTokenResponseClient(this.accessTokenResponseClient());
            }
        }
      
    • ClientRegistration:客户端注册

      • 客户端注册包含信息,如客户端id、客户端机密、授权授予类型、重定向URI、范围、授权URI、令牌URI和其他详细信息。
      •   public final class ClientRegistration {
              private String registrationId;  //唯一标识ClientRegistration(客户注册)的ID。
              private String clientId;    //客户端标识符
              private String clientSecret;    //客户端秘钥
              private ClientAuthenticationMethod clientAuthenticationMethod;  //使用提供程序对客户端进行身份验证的方法
              private AuthorizationGrantType authorizationGrantType;  //OAuth 2.0授权框架定义了四种授权授权类型。支持的值是authorization_code、隐式值和client_credentials。
              private String redirectUriTemplate; //在最终用户对客户机进行了身份验证和授权访问之后,授权服务器将客户机注册的重定向URI重定向到终端用户的用户代理。
              private Set scopes; //客户端在授权请求流(如openid、电子邮件或配置文件)期间请求的范围。
              private ProviderDetails providerDetails;
              private String clientName;  //用于客户端的描述性名称。该名称可用于某些场景,例如在自动生成的登录页面中显示客户端名称时。
        
              public class ProviderDetails {
                  private String authorizationUri;    //授权服务器的授权端点URI。
                  private String tokenUri;   //授权服务器的令牌端点URI。
                  private UserInfoEndpoint userInfoEndpoint;
                  private String jwkSetUri;   //用于从授权服务器检索JSON Web Key (JWK)集的URI,其中包含用于验证ID令牌的JSON Web签名(JWS)和可选的UserInfo响应的加密密钥。
                  private Map configurationMetadata;  //OpenID提供程序配置信息。此信息仅在Spring Boot 2中可用。
        
                  public class UserInfoEndpoint {
                      private String uri; //用于访问经过身份验证的最终用户的声明/属性的UserInfo端点URI。
                      private AuthenticationMethod authenticationMethod;  //将访问令牌发送到UserInfo端点时使用的身份验证方法。支持的值是头、表单和查询。
                      private String userNameAttributeName;   //UserInfo响应中返回的属性的名称,该属性引用最终用户的名称或标识符。
                  }
              }
          }
        
        
    • ClientRegistrationRepository:ClientRegistrationRepository用作OAuth 2.0的存储库

      • 客户机注册信息最终由关联的授权服务器存储和拥有。此存储库提供检索主客户端注册信息子集的功能,这些信息存储在授权服务器中。
      • Spring Boot 2.x auto-configuration 绑定下面的每个属性 spring.security.oauth2.client.registration.[registrationId] 的实例,然后将其组合为 ClientRegistration instance(s) within a ClientRegistrationRepository.
        • ClientRegistrationRepository的默认实现是InMemoryClientRegistrationRepository。
      • 自动配置还将ClientRegistrationRepository注册为ApplicationContext中的@Bean,以便在应用程序需要时可以对其进行依赖注入。
    • OAuth2AuthorizedClient: 授权客户端

      • 当最终用户(资源所有者)向客户机授予访问其受保护资源的授权时,将认为客户机已获得授权。
      • OAuth2AuthorizedClient的作用是将OAuth2AccessToken(以及可选的OAuth2RefreshToken)关联到客户机注册(客户机)和资源所有者,后者是授予授权的主要最终用户。
    • OAuth2AuthorizedClientRepository / OAuth2AuthorizedClientService

      • OAuth2AuthorizedClientRepository负责在web请求之间持久化OAuth2AuthorizedClient。然而,OAuth2AuthorizedClientService的主要角色是在应用程序级管理OAuth2AuthorizedClient。
      • 从开发人员的角度来看,OAuth2AuthorizedClientRepository或OAuth2AuthorizedClientService提供了查找与客户机关联的OAuth2AccessToken的功能,以便可以使用它来发起受保护的资源请求。
      • Spring Boot 2.x auto-configuration registers an OAuth2AuthorizedClientRepository and/or OAuth2AuthorizedClientService @Bean in the ApplicationContext.
      • 开发人员还可以在ApplicationContext中注册一个OAuth2AuthorizedClientRepository或OAuth2AuthorizedClientService @Bean(覆盖Spring Boot 2)。x自动配置),以便能够查找与特定客户注册(client)关联的OAuth2AccessToken。
      •   @Controller
          public class OAuth2LoginController {
        
              @Autowired
              private OAuth2AuthorizedClientService authorizedClientService;
        
              @RequestMapping("/userinfo")
              public String userinfo(OAuth2AuthenticationToken authentication) {
                  // authentication.getAuthorizedClientRegistrationId() returns the
                  // registrationId of the Client that was authorized during the oauth2Login() flow
                  OAuth2AuthorizedClient authorizedClient =
                      this.authorizedClientService.loadAuthorizedClient(
                          authentication.getAuthorizedClientRegistrationId(),
                          authentication.getName());
        
                  OAuth2AccessToken accessToken = authorizedClient.getAccessToken();
        
                  ...
        
                  return "userinfo";
              }
          }
        
        
    • RegisteredOAuth2AuthorizedClient:

      • @RegisteredOAuth2AuthorizedClient注释提供了将方法参数解析为OAuth2AuthorizedClient类型的参数值的功能。与通过OAuth2AuthorizedClientService查找OAuth2AuthorizedClient相比,这是一种方便的选择。
      •   @Controller
          public class OAuth2LoginController {
        
              @RequestMapping("/userinfo")
              public String userinfo(@RegisteredOAuth2AuthorizedClient("google") OAuth2AuthorizedClient authorizedClient) {
                  OAuth2AccessToken accessToken = authorizedClient.getAccessToken();
        
                  ...
        
                  return "userinfo";
              }
          }
        
      • @RegisteredOAuth2AuthorizedClient注释由OAuth2AuthorizedClientArgumentResolver处理,并提供以下功能:
        • 如果客户端尚未获得授权,将自动请求OAuth2AccessToken。
          • 对于authorization_code,这涉及触发授权请求重定向以启动流
          • 对于client_credentials,使用DefaultClientCredentialsTokenResponseClient直接从令牌端点获得访问令牌
    • AuthorizationRequestRepository:

      • AuthorizationRequestRepository负责OAuth2AuthorizationRequest从启动授权请求到接收授权响应(回调)期间的持久性。
      • OAuth2AuthorizationRequest用于关联和验证授权响应。
      • AuthorizationRequestRepository的默认实现是HttpSessionOAuth2AuthorizationRequestRepository,它将OAuth2AuthorizationRequest存储在HttpSession中。
      • 如果您想提供AuthorizationRequestRepository的自定义实现,该实现将OAuth2AuthorizationRequest的属性存储在Cookie中,您可以对其进行如下配置:
        •   @EnableWebSecurity
            public class OAuth2ClientSecurityConfig extends WebSecurityConfigurerAdapter {
          
                @Override
                protected void configure(HttpSecurity http) throws Exception {
                    http
                        .oauth2Client()
                            .authorizationCodeGrant()
                                .authorizationRequestRepository(this.cookieAuthorizationRequestRepository())
                                ...
                }
          
                private AuthorizationRequestRepository cookieAuthorizationRequestRepository() {
                    return new HttpCookieOAuth2AuthorizationRequestRepository();
                }
            }
          
          
    • OAuth2AuthorizationRequestResolver: 从提供的web请求中解析一个OAuth2AuthorizationRequest。

      • OAuth2AuthorizationRequestResolver的主要角色是从提供的web请求解析OAuth2AuthorizationRequest。
      • 默认实现DefaultOAuth2AuthorizationRequestResolver在(默认)路径/oauth2/authorization/{registrationId}上匹配,该路径提取registrationId并使用它为关联的客户注册构建OAuth2AuthorizationRequest。
      • OAuth2AuthorizationRequestResolver可以实现的主要用例之一是,使用OAuth 2.0授权框架中定义的标准参数之上的额外参数来定制授权请求。
      • 下面的示例展示了如何实现一个OAuth2AuthorizationRequestResolver,它通过包含请求参数prompt=consent来定制oauth2Login()的授权请求。
        •   @EnableWebSecurity
            public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
          
                @Autowired
                private ClientRegistrationRepository clientRegistrationRepository;
          
                @Override
                protected void configure(HttpSecurity http) throws Exception {
                    http
                        .authorizeRequests()
                            .anyRequest().authenticated()
                            .and()
                        .oauth2Login()
                            .authorizationEndpoint()
                                .authorizationRequestResolver(
                                        new CustomAuthorizationRequestResolver(
                                                this.clientRegistrationRepository));    //配置自定义OAuth2AuthorizationRequestResolver
                }
            }
          
            public class CustomAuthorizationRequestResolver implements OAuth2AuthorizationRequestResolver {
                private final OAuth2AuthorizationRequestResolver defaultAuthorizationRequestResolver;
          
                public CustomAuthorizationRequestResolver(
                        ClientRegistrationRepository clientRegistrationRepository) {
          
                    this.defaultAuthorizationRequestResolver =
                            new DefaultOAuth2AuthorizationRequestResolver(
                                    clientRegistrationRepository, "/oauth2/authorization");
                }
          
                @Override
                public OAuth2AuthorizationRequest resolve(HttpServletRequest request) {
                    OAuth2AuthorizationRequest authorizationRequest =
                            this.defaultAuthorizationRequestResolver.resolve(request);  //尝试使用DefaultOAuth2AuthorizationRequestResolver解析OAuth2AuthorizationRequest
          
                    return authorizationRequest != null ?   //如果OAuth2AuthorizationRequest被解析,则返回定制的版本,否则返回null
                            customAuthorizationRequest(authorizationRequest) :
                            null;
                }
          
                @Override
                public OAuth2AuthorizationRequest resolve(
                        HttpServletRequest request, String clientRegistrationId) {
          
                    OAuth2AuthorizationRequest authorizationRequest =
                            this.defaultAuthorizationRequestResolver.resolve(
                                request, clientRegistrationId);    //尝试使用DefaultOAuth2AuthorizationRequestResolver解析OAuth2AuthorizationRequest
          
                    return authorizationRequest != null ?   //如果OAuth2AuthorizationRequest被解析,则返回定制的版本,否则返回null
                            customAuthorizationRequest(authorizationRequest) :
                            null;
                }
          
                private OAuth2AuthorizationRequest customAuthorizationRequest(
                        OAuth2AuthorizationRequest authorizationRequest) {
          
                    Map additionalParameters =
                            new LinkedHashMap<>(authorizationRequest.getAdditionalParameters());
                    additionalParameters.put("prompt", "consent");  //向现有的OAuth2AuthorizationRequest.additionalParameters添加自定义参数
          
                    return OAuth2AuthorizationRequest.from(authorizationRequest)    //创建默认OAuth2AuthorizationRequest的副本,该副本返回一个OAuth2AuthorizationRequest。进一步修改的构建器
                            .additionalParameters(additionalParameters) //覆盖默认的additionalParameters
                            .build();
                }
            }
          
        • OAuth2AuthorizationRequest.Builder.build() 构建出 OAuth2AuthorizationRequest.authorizationRequestUri, 哪个表示完整的授权请求URI,包括使用的所有查询参数 the application/x-www-form-urlencoded 格式.
      • 如果您需要删除或更改标准参数,或者您的需求更为高级,那么您可以通过简单地覆盖OAuth2AuthorizationRequest.authorizationRequestUri property
        • 下面的示例显示了来自前一个示例的customAuthorizationRequest()方法的变体,并覆盖了OAuth2AuthorizationRequest。authorizationRequestUri property。
          •   private OAuth2AuthorizationRequest customAuthorizationRequest(
                      OAuth2AuthorizationRequest authorizationRequest) {
            
                  String customAuthorizationRequestUri = UriComponentsBuilder
                          .fromUriString(authorizationRequest.getAuthorizationRequestUri())
                          .queryParam("prompt", "consent")
                          .build(true)
                          .toUriString();
            
                  return OAuth2AuthorizationRequest.from(authorizationRequest)
                          .authorizationRequestUri(customAuthorizationRequestUri)
                          .build();
              }
            
    • OAuth2AccessTokenResponseClient: OAuth2AccessTokenResponseClient的主要角色是在授权服务器的令牌端点将授权授予凭据交换为访问令牌凭据。

      • 对于authorization_code授权,OAuth2AccessTokenResponseClient的默认实现是DefaultAuthorizationCodeTokenResponseClient,它使用RestOperations在令牌端点将授权代码交换为访问令牌。
        • DefaultAuthorizationCodeTokenResponseClient非常灵活,因为它允许您定制令牌请求的预处理和/或令牌响应的后处理。
        • 如果需要定制令牌请求的预处理,可以提供
          • DefaultAuthorizationCodeTokenResponseClient.setRequestEntityConverter() 与一个定制
          • Converter>. 默认实现
          • OAuth2AuthorizationCodeGrantRequestEntityConverter builds a RequestEntity 标准OAuth 2.0访问令牌请求的表示。但是,提供自定义转换器将允许您扩展标准令牌请求并添加自定义参数。
            • 自定义 Converter 必须返回有效的 OAuth 2.0访问令牌请求的RequestEntity表示,该请求由预期的OAuth 2.0提供者理解。
        • 另一方面,如果需要定制令牌响应的后处理,则需要使用自定义配置的RestOperations()提供DefaultAuthorizationCodeTokenResponseClient.setRestOperations()。默认的RestOperations配置如下:
          •   RestTemplate restTemplate = new RestTemplate(Arrays.asList(
                      new FormHttpMessageConverter(),//当发送OAuth 2.0访问令牌请求时,需要使用Spring MVC FormHttpMessageConverter。
                      new OAuth2AccessTokenResponseHttpMessageConverter()));
            
              restTemplate.setErrorHandler(new OAuth2ErrorResponseErrorHandler());
            
            
          • OAuth2AccessTokenResponseHttpMessageConverter是OAuth 2.0访问令牌响应的HttpMessageConverter。您可以提供

          • 带有自定义的OAuth2AccessTokenResponseHttpMessageConverter.setTokenResponseConverter()

          • Converter, OAuth2AccessTokenResponse> 用于将OAuth 2.0访问令牌响应参数转换为OAuth2AccessTokenResponse。

          • OAuth2ErrorResponseErrorHandler是一个ResponseErrorHandler,它可以处理OAuth 2.0错误(400个错误请求)。它使用一个

          • OAuth2ErrorHttpMessageConverter 用于将OAuth 2.0错误参数转换为OAuth2Error。

      • 无论您是定制DefaultAuthorizationCodeTokenResponseClient,还是提供您自己的OAuth2AccessTokenResponseClient实现,您都需要对其进行配置,如下面的示例所示:
        •   @EnableWebSecurity
            public class OAuth2ClientSecurityConfig extends WebSecurityConfigurerAdapter {
          
                @Override
                protected void configure(HttpSecurity http) throws Exception {
                    http
                        .oauth2Client()
                            .authorizationCodeGrant()
                                .accessTokenResponseClient(this.customAccessTokenResponseClient())
                                ...
                }
          
                private OAuth2AccessTokenResponseClient customAccessTokenResponseClient() {
                    ...
                }
            }
          
          
OAuth 2.0 Login
  • 步骤:
    • 获取授权服务器的clientId,clientSecret

    • 设置重定向URL

      • The default redirect URI template is {baseUrl}/login/oauth2/code/{registrationId}. The registrationId is a unique identifier for the ClientRegistration.
    • application.yml文件配置

      •   spring:
            security:
              oauth2:
                client:
                  registration:   //OAuth客户端属性的基本属性前缀
                    google:   //在基本属性前缀后面是客户机注册的ID,比如谷歌。( registrationId (google) matches the GOOGLE enum (case-insensitive))
                      client-id: google-client-id
                      client-secret: google-client-secret
        
        
    • Spring Boot 2.x Property Mappings:

      • 下表概述了Spring Boot 2的映射。将客户端属性设置为客户注册属性:
        • Spring Boot 2.x ClientRegistration
          spring.security.oauth2.client.registration.[registrationId] registrationId
          spring.security.oauth2.client.registration.[registrationId].client-id clientId
          spring.security.oauth2.client.registration.[registrationId].client-secret clientSecret
          spring.security.oauth2.client.registration.[registrationId].client-authentication-method clientAuthenticationMethod
          spring.security.oauth2.client.registration.[registrationId].authorization-grant-type authorizationGrantType
          spring.security.oauth2.client.registration.[registrationId].redirect-uri redirectUriTemplate
          spring.security.oauth2.client.registration.[registrationId].scope scopes
          spring.security.oauth2.client.registration.[registrationId].client-name clientName
          spring.security.oauth2.client.provider.[providerId].authorization-uri providerDetails.authorizationUri
          spring.security.oauth2.client.provider.[providerId].token-uri providerDetails.tokenUri
          spring.security.oauth2.client.provider.[providerId].jwk-set-uri providerDetails.jwkSetUri
          spring.security.oauth2.client.provider.[providerId].user-info-uri providerDetails.userInfoEndpoint.uri
          spring.security.oauth2.client.provider.[providerId].user-info-authentication-method providerDetails.userInfoEndpoint.authenticationMethod
          spring.security.oauth2.client.provider.[providerId].userNameAttribute providerDetails.userInfoEndpoint.userNameAttributeName
    • CommonOAuth2Provider:Oauth2.0 服务提供者

      • the authorization-uri, token-uri, and user-info-uri 对于提供者,不要经常更改。因此,为了减少所需的配置,提供默认值是有意义的。
    • 配置自定义Provider属性

      • 有些OAuth 2.0提供程序支持多租户,这导致每个租户(或子域)的协议端点不同。
    • 重写 Spring Boot 2.x Auto-configuration

      • The Spring Boot 2.x auto-configuration class for OAuth Client support is OAuth2ClientAutoConfiguration.
        • Oauth2ClientAutoConfiguration它执行以下任务:
          • Registers a ClientRegistrationRepository @Bean composed of ClientRegistration(s) from the configured OAuth Client properties.
          • Provides a WebSecurityConfigurerAdapter @Configuration and enables OAuth 2.0 Login through httpSecurity.oauth2Login().
        • 如果你需要复写auto-configuration 根据你的具体要求,你可采用以下方法:
          • Register a ClientRegistrationRepository @Bean
            •   @Configuration
                public class OAuth2LoginConfig {
              
                    @Bean
                    public ClientRegistrationRepository clientRegistrationRepository() {
                        return new InMemoryClientRegistrationRepository(this.googleClientRegistration());
                    }
              
                    private ClientRegistration googleClientRegistration() {
                        return ClientRegistration.withRegistrationId("google")
                            .clientId("google-client-id")
                            .clientSecret("google-client-secret")
                            .clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
                            .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
                            .redirectUriTemplate("{baseUrl}/login/oauth2/code/{registrationId}")
                            .scope("openid", "profile", "email", "address", "phone")
                            .authorizationUri("https://accounts.google.com/o/oauth2/v2/auth")
                            .tokenUri("https://www.googleapis.com/oauth2/v4/token")
                            .userInfoUri("https://www.googleapis.com/oauth2/v3/userinfo")
                            .userNameAttributeName(IdTokenClaimNames.SUB)
                            .jwkSetUri("https://www.googleapis.com/oauth2/v3/certs")
                            .clientName("Google")
                            .build();
                    }
                }
              
          • Provide a WebSecurityConfigurerAdapter
            •   @EnableWebSecurity
                public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
              
                    @Override
                    protected void configure(HttpSecurity http) throws Exception {
                        http
                            .authorizeRequests()
                                .anyRequest().authenticated()
                                .and()
                            .oauth2Login();
                    }
                }
              
          • Completely Override the Auto-configuration
            • 下面的示例展示了如何通过注册ClientRegistrationRepository @Bean并提供WebSecurityConfigurerAdapter来完全覆盖自动配置。
            •   @Configuration
                public class OAuth2LoginConfig {
              
                    @EnableWebSecurity
                    public static class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
              
                        @Override
                        protected void configure(HttpSecurity http) throws Exception {
                            http
                                .authorizeRequests()
                                    .anyRequest().authenticated()
                                    .and()
                                .oauth2Login();
                        }
                    }
              
                    @Bean
                    public ClientRegistrationRepository clientRegistrationRepository() {
                        return new InMemoryClientRegistrationRepository(this.googleClientRegistration());
                    }
              
                    private ClientRegistration googleClientRegistration() {
                        return ClientRegistration.withRegistrationId("google")
                            .clientId("google-client-id")
                            .clientSecret("google-client-secret")
                            .clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
                            .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
                            .redirectUriTemplate("{baseUrl}/login/oauth2/code/{registrationId}")
                            .scope("openid", "profile", "email", "address", "phone")
                            .authorizationUri("https://accounts.google.com/o/oauth2/v2/auth")
                            .tokenUri("https://www.googleapis.com/oauth2/v4/token")
                            .userInfoUri("https://www.googleapis.com/oauth2/v3/userinfo")
                            .userNameAttributeName(IdTokenClaimNames.SUB)
                            .jwkSetUri("https://www.googleapis.com/oauth2/v3/certs")
                            .clientName("Google")
                            .build();
                    }
                }
              

OAuth 2.0 Resource Server 资源服务器

  • Spring Security支持使用jwt编码的OAuth 2.0承载令牌保护端点
  • 在使用Spring Boot时,将应用程序配置为资源服务器包括两个基本步骤。首先,包括所需的依赖项,其次,指示授权服务器的位置。
  • 多重HttpSecurity配置
    •   @EnableWebSecurity
        public class MultiHttpSecurityConfig {
            @Bean  //正常配置身份验证
            public UserDetailsService userDetailsService() throws Exception {
                // ensure the passwords are encoded properly
                UserBuilder users = User.withDefaultPasswordEncoder();
                InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
                manager.createUser(users.username("user").password("password").roles("USER").build());
                manager.createUser(users.username("admin").password("password").roles("USER","ADMIN").build());
                return manager;
            }
      
            @Configuration
            @Order(1) //创建一个包含@Order的WebSecurityConfigurerAdapter实例,以指定应该首先考虑哪个WebSecurityConfigurerAdapter。
            public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
                protected void configure(HttpSecurity http) throws Exception {
                    http
                        .antMatcher("/api/**")   //http.antMatcher声明此HttpSecurity只适用于以/api/开头的url
                        .authorizeRequests()
                            .anyRequest().hasRole("ADMIN")
                            .and()
                        .httpBasic();
                }
            }
      
            @Configuration   //创建WebSecurityConfigurerAdapter的另一个实例。如果URL不以/api/开头,将使用此配置。这个配置是在ApiWebSecurityConfigurationAdapter之后考虑的,因为它在1之后有一个@Order值(没有@Order默认值是last)。
            public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
      
                @Override
                protected void configure(HttpSecurity http) throws Exception {
                    http
                        .authorizeRequests()
                            .anyRequest().authenticated()
                            .and()
                        .formLogin();
                }
            }
        }
      
  • @Secured 方法安全
    • 从2.0版本开始,Spring Security大大改进了对向服务层方法添加安全性的支持。
    • 它支持JSR-250注释安全性以及框架的原始@ secure注释。从3.0开始,您还可以使用新的基于表达式的注释。
    • 您可以对单个bean应用安全性,使用intercept-methods元素装饰bean声明,或者使用AspectJ样式的切入点跨整个服务层保护多个bean。
  • @EnableGlobalMethodSecurity 全局方法安全
    • 我们可以在任何@Configuration实例上使用@EnableGlobalMethodSecurity注释来启用基于注释的安全性。
    •   @EnableGlobalMethodSecurity(securedEnabled = true)
        public class MethodSecurityConfig {
        // ...
        }
      
    • 向方法(在类或接口上)添加注释将相应地限制对该方法的访问。Spring Security的本机注释支持为该方法定义一组属性。这些信息将被传递给AccessDecisionManager,由它来做出实际的决定:
    •   public interface BankService {
      
        @Secured("IS_AUTHENTICATED_ANONYMOUSLY")
        public Account readAccount(Long id);
      
        @Secured("IS_AUTHENTICATED_ANONYMOUSLY")
        public Account[] findAccounts();
      
        @Secured("ROLE_TELLER")
        public Account post(Account account, double amount);
        }
      
  • GlobalMethodSecurityConfiguration
    • 有时您可能需要执行比@EnableGlobalMethodSecurity注释allow更复杂的操作。对于这些实例,您可以扩展GlobalMethodSecurityConfiguration,确保@EnableGlobalMethodSecurity注释出现在您的子类上。例如,如果您想提供一个定制的MethodSecurityExpressionHandler,您可以使用以下配置:
      •   @EnableGlobalMethodSecurity(prePostEnabled = true)
          public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
              @Override
              protected MethodSecurityExpressionHandler createExpressionHandler() {
                  // ... create and return custom MethodSecurityExpressionHandler ...
                  return expressionHandler;
              }
          }
        
OAuth 2.0 Login — Advanced Configuration
  • oauth2login()为定制OAuth 2.0登录提供了许多配置选项。将主要配置选项分组到它们的协议端点对应项中。
  • 例如,oauth2Login(). authorizationendpoint()允许配置授权端点,而oauth2Login(). tokenendpoint()允许配置令牌端点。
    •   @EnableWebSecurity
        public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
      
            @Override
            protected void configure(HttpSecurity http) throws Exception {
                http
                    .oauth2Login()
                        .clientRegistrationRepository(this.clientRegistrationRepository())
                        .authorizedClientRepository(this.authorizedClientRepository())
                        .authorizedClientService(this.authorizedClientService())
                        .loginPage("/login/oauth2")//您需要提供一个具有@RequestMapping("/login/oauth2")的@Controller,该映射能够呈现自定义登录页面。
                        .authorizationEndpoint()//授权端点:客户机用于通过用户代理重定向从资源所有者获得授权。
                            .baseUri(this.authorizationRequestBaseUri())
                            .authorizationRequestRepository(this.authorizationRequestRepository())
                            .authorizationRequestResolver(this.authorizationRequestResolver())
                            .and()
                        .redirectionEndpoint()//授权服务器使用重定向端点通过资源所有者user-agent将授权响应(包含授权凭据)返回给客户机。
                            .baseUri(this.authorizationResponseBaseUri())//OAuth 2.0登录利用授权代码授予。因此,授权凭证就是授权代码。
                            .and()
                        .tokenEndpoint()//令牌端点:客户端用于交换访问令牌的授权授予,通常使用客户端身份验证。
                            .accessTokenResponseClient(this.accessTokenResponseClient())
                            .and()
                        .userInfoEndpoint()
                            .userAuthoritiesMapper(this.userAuthoritiesMapper())
                            .userService(this.oauth2UserService())
                            .oidcUserService(this.oidcUserService())
                            .customUserType(GitHubOAuth2User.class, "github");
            }
        }
      
    • 您还需要确保客户注册。redirectUriTemplate匹配自定义授权响应baseUri。
      •   return CommonOAuth2Provider.GOOGLE.getBuilder("google")
              .clientId("google-client-id")
              .clientSecret("google-client-secret")
              .redirectUriTemplate("{baseUrl}/login/oauth2/callback/{registrationId}")
              .build();
        
    • UserInfo Endpoint:
      • UserInfo端点包含许多配置选项,如下面的小节所述:
        • Mapping User Authorities
          • 在用户成功地通过OAuth 2.0提供者的身份验证之后,可以将OAuth2User.getAuthorities() (or OidcUser.getAuthorities()) 映射到一组新的授予的GrantedAuthority实例,这些实例将在完成身份验证时提供给OAuth2AuthenticationToken。
          • OAuth2AuthenticationToken.getAuthorities() is used for authorizing requests, such as in hasRole(‘USER’) or hasRole(‘ADMIN’).
          • 在映射用户权限时,有几个选项可供选择:
            • Using a GrantedAuthoritiesMapper
              • 提供一个GrantedAuthoritiesMapper的实现并进行配置,如下例所示:
                •   @EnableWebSecurity
                    public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
                  
                        @Override
                        protected void configure(HttpSecurity http) throws Exception {
                            http
                                .oauth2Login()
                                    .userInfoEndpoint()
                                        .userAuthoritiesMapper(this.userAuthoritiesMapper())
                                        ...
                        }
                  
                        private GrantedAuthoritiesMapper userAuthoritiesMapper() {
                            return (authorities) -> {
                                Set mappedAuthorities = new HashSet<>();
                  
                                authorities.forEach(authority -> {
                                    if (OidcUserAuthority.class.isInstance(authority)) {
                                        OidcUserAuthority oidcUserAuthority = (OidcUserAuthority)authority;
                  
                                        OidcIdToken idToken = oidcUserAuthority.getIdToken();
                                        OidcUserInfo userInfo = oidcUserAuthority.getUserInfo();
                  
                                        // Map the claims found in idToken and/or userInfo
                                        // to one or more GrantedAuthority's and add it to mappedAuthorities
                  
                                    } else if (OAuth2UserAuthority.class.isInstance(authority)) {
                                        OAuth2UserAuthority oauth2UserAuthority = (OAuth2UserAuthority)authority;
                  
                                        Map userAttributes = oauth2UserAuthority.getAttributes();
                  
                                        // Map the attributes found in userAttributes
                                        // to one or more GrantedAuthority's and add it to mappedAuthorities
                  
                                    }
                                });
                  
                                return mappedAuthorities;
                            };
                        }
                    }
                  
                • 或者,您可以注册一个GrantedAuthoritiesMapper @Bean,让它自动应用到配置中,如下面的示例所示:
                  •   @EnableWebSecurity
                      public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
                    
                          @Override
                          protected void configure(HttpSecurity http) throws Exception {
                              http.oauth2Login();
                          }
                    
                          @Bean
                          public GrantedAuthoritiesMapper userAuthoritiesMapper() {
                              ...
                          }
                      }
                    
            • Delegation-based strategy with OAuth2UserService
              • 与使用GrantedAuthoritiesMapper相比,此策略更高级,但是,它也更灵活,因为它允许您访问OAuth2UserRequest和OAuth2User(在使用OAuth 2.0 UserService时)或OidcUserRequest和OidcUser(在使用OpenID Connect 1.0 UserService时)。
              • OAuth2UserRequest(和OidcUserRequest)为您提供了对关联的OAuth2AccessToken的访问,这在委托程序需要从受保护的资源中获取权限信息,然后才能为用户映射自定义权限的情况下非常有用。
        • Configuring a Custom OAuth2User
          • CustomUserTypesOAuth2UserService是OAuth2UserService的实现,它提供了对定制OAuth2User类型的支持。
          • 如果默认实现(DefaultOAuth2User)不适合您的需要,您可以定义自己的OAuth2User实现。
          • 下面的代码演示了如何为GitHub注册自定义OAuth2User类型:
            •   @EnableWebSecurity
                public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
              
                    @Override
                    protected void configure(HttpSecurity http) throws Exception {
                        http
                            .oauth2Login()
                                .userInfoEndpoint()
                                    .customUserType(GitHubOAuth2User.class, "github")
                                    ...
                    }
                }
              
          • 下面的代码展示了一个为GitHub定制的OAuth2User类型的例子:
            •   public class GitHubOAuth2User implements OAuth2User {
                    private List authorities =
                        AuthorityUtils.createAuthorityList("ROLE_USER");
                    private Map attributes;
                    private String id;
                    private String name;
                    private String login;
                    private String email;
              
                    @Override
                    public Collection getAuthorities() {
                        return this.authorities;
                    }
              
                    @Override
                    public Map getAttributes() {
                        if (this.attributes == null) {
                            this.attributes = new HashMap<>();
                            this.attributes.put("id", this.getId());
                            this.attributes.put("name", this.getName());
                            this.attributes.put("login", this.getLogin());
                            this.attributes.put("email", this.getEmail());
                        }
                        return attributes;
                    }
              
                    省略getter、setter方法
                }
              
            • id、name、login和email是GitHub的UserInfo响应中返回的属性。
        • OAuth 2.0 UserService
          • DefaultOAuth2UserService是支持标准OAuth 2.0提供者的OAuth2UserService的实现。
            • OAuth2UserService从UserInfo端点获得最终用户(资源所有者)的用户属性(通过使用在授权流期间授予客户机的访问令牌),并以OAuth2User的形式返回AuthenticatedPrincipal。
            • DefaultOAuth2UserService在UserInfo端点请求用户属性时使用RestOperations。
          • 如果需要定制UserInfo请求的预处理,可以使用自定义转换器>提供DefaultOAuth2UserService.setRequestEntityConverter()。默认实现OAuth2UserRequestEntityConverter构建UserInfo请求的RequestEntity表示形式,该请求在默认情况下设置授权头中的OAuth2AccessToken。
          • 另一方面,如果需要自定义UserInfo响应的后处理,则需要使用自定义配置的RestOperations()提供DefaultOAuth2UserService.setRestOperations()。默认的RestOperations配置如下:
            •   RestTemplate restTemplate = new RestTemplate();
                restTemplate.setErrorHandler(new OAuth2ErrorResponseErrorHandler());
              
            • OAuth2ErrorResponseErrorHandler is a ResponseErrorHandler that can handle an OAuth 2.0 Error (400 Bad Request). It uses an
            • OAuth2ErrorHttpMessageConverter for converting the OAuth 2.0 Error parameters to an OAuth2Error.
            • 无论您是自定义DefaultOAuth2UserService还是提供自己的OAuth2UserService实现,您都需要对其进行配置,如下面的示例所示:
              •   @EnableWebSecurity
                  public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
                
                      @Override
                      protected void configure(HttpSecurity http) throws Exception {
                          http
                              .oauth2Login()
                                  .userInfoEndpoint()
                                      .userService(this.oauth2UserService())
                                      ...
                      }
                
                      private OAuth2UserService oauth2UserService() {
                          ...
                      }
                  }
                
        • OpenID Connect 1.0 UserService
          • OidcUserService是支持OpenID Connect 1.0提供者的OAuth2UserService的实现。

Security Core Services

  • 现在我们已经对Spring安全体系结构及其核心类有了一个高层次的概述,接下来让我们更仔细地研究一两个核心接口及其实现,特别是AuthenticationManager、UserDetailsService和AccessDecisionManager。在本文档的其余部分中,这些内容会定期出现,因此了解它们的配置和操作方式非常重要。

  • The AuthenticationManager, ProviderManager and AuthenticationProvider

    • AuthenticationManager只是一个接口,所以实现可以是我们选择的任何东西,但是它在实践中是如何工作的呢?如果我们需要检查多个身份验证数据库或不同身份验证服务(如数据库和LDAP服务器)的组合,该怎么办?
    • Spring Security中的默认实现称为ProviderManager,而不是处理身份验证请求本身,它将委托给一组已配置的AuthenticationProvider,依次查询每个AuthenticationProvider,以查看它是否能够执行身份验证。每个提供者要么抛出一个异常,要么返回一个完整填充的身份验证对象。还记得我们的好朋友,用户细节和用户细节服务吗?如果没有,回到上一章,刷新你的记忆。验证身份验证请求的最常见方法是加载相应的UserDeta
    • 如果使用名称空间,则在内部创建和维护ProviderManager的实例,并使用名称空间身份验证提供程序元素将提供程序添加到其中(请参阅名称空间一章)。在这种情况下,您不应该在应用程序上下文中声明ProviderManager bean。
  • DaoAuthenticationProvider

    • pring Security实现的最简单的身份验证提供者是DaoAuthenticationProvider,它也是框架最早支持的提供者之一。它利用UserDetailsService(作为DAO)来查找用户名、密码和授予的权限。它通过将UsernamePasswordAuthenticationToken中提交的密码与UserDetailsService加载的密码进行比较来验证用户。配置提供程序非常简单:
      •   
          
          
          
        
    • 密码编码器是可选的。PasswordEncoder提供从配置的UserDetailsService返回的UserDetails对象中显示的密码的编码和解码。
  • UserDetailsService Implementations

    • 多数身份验证提供者都利用了UserDetails和UserDetailsService接口。回想一下,UserDetailsService的契约是一个方法:
      •   UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
        
    • 返回的UserDetails是一个提供getter的接口,它保证身份验证信息的非空提供,比如用户名、密码、授予的权限以及用户帐户是启用还是禁用。大多数身份验证提供者将使用UserDetailsService,即使用户名和密码实际上不是身份验证决策的一部分。
  • In-Memory Authentication

    • 创建一个自定义UserDetailsService实现很容易使用,它可以从选择的持久性引擎中提取信息,但是许多应用程序不需要这么复杂。如果您正在构建原型应用程序或刚刚开始集成Spring安全性,而又不想花时间配置数据库或编写UserDetailsService实现,那么这一点尤其重要。对于这种情况,一个简单的选项是使用来自安全命名空间的user-service元素:
      •   
          
          
          
          
        
    • Spring Security还包括一个UserDetailsService,它可以从JDBC数据源获取身份验证信息。在内部使用了Spring JDBC,因此它避免了只存储用户详细信息的全功能对象关系映射器(ORM)的复杂性。如果您的应用程序确实使用ORM工具,您可能更愿意编写一个定制的UserDetailsService来重用您可能已经创建的映射文件。
      •   
          
          
          
          
          
        
          
          
          
        
        
Password Encoding:
  • Spring Security的PasswordEncoder接口用于执行密码的单向转换,以允许安全地存储密码。给定PasswordEncoder是一种单向转换,当密码转换需要是两种方式(即存储用于对数据库进行身份验证的凭据)时,就不打算这样做。通常PasswordEncoder用于存储在身份验证时需要与用户提供的密码进行比较的密码。
  • DelegatingPasswordEncoder: 委派加密算法
    • 您可以使用PasswordEncoderFactories轻松构造一个委托passwordencoder的实例:
      •   String idForEncode = "bcrypt";
          Map encoders = new HashMap<>();
          encoders.put(idForEncode, new BCryptPasswordEncoder());
          encoders.put("noop", NoOpPasswordEncoder.getInstance());
          encoders.put("pbkdf2", new Pbkdf2PasswordEncoder());
          encoders.put("scrypt", new SCryptPasswordEncoder());
          encoders.put("sha256", new StandardPasswordEncoder());
        
          PasswordEncoder passwordEncoder =
              new DelegatingPasswordEncoder(idForEncode, encoders);
        
  • Password Storage Format(密码存储格式):
    • {id}encodedPassword
    • id是用于查找应该使用哪个PasswordEncoder的标识符,encodedPassword是所选PasswordEncoder的原始编码密码。id必须位于密码的开头,以{开头,以}结尾。如果找不到id,则id为null。例如,下面可能是使用不同id编码的密码列表。所有原始密码都是“password”。
      •   {bcrypt}$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG //密码编解码器id为bcrypt,匹配时将委托给BCryptPasswordEncoder
          {noop}password //密码将具有noop的PasswordEncoder id和encodedPassword的password。匹配时将委托给NoOpPasswordEncoder
          {pbkdf2}5d923b44a6d129f3ddf3e3c8d29412723dcbde72445e8ef6bf3b508fbf17fa4ed4d6b99ca763d8dc //密码编解码器id为pbkdf2,匹配时将委托给Pbkdf2PasswordEncoder
          {scrypt}$e0801$8bWJaSu2IKSn9Z9kM+TPXfOc/9bdYSrN1oD9qfVThWEwdRTnO7re7Ei+fUZRJ68k9lTyuTeUp4of4g24hHnazw==$OAOec05+bXxvuu/1qZ6NUR+xQYvYv7BeL1QxwRpY5Pc=  //密码为scrypt的PasswordEncoder 匹配时委托给scryptpasswordender
          {sha256}97cde38028ad898ebc02e690819fa220e88c62e0699403e94fff291cfffaf8410849f27605abcbc0 //密码为sha256,匹配时将委托给StandardPasswordEncoder
        
  • BCryptPasswordEncoder:
    • BCryptPasswordEncoder实现使用广泛支持的bcrypt算法来散列密码。为了使其更能抵抗密码破解,bcrypt故意放慢了速度。与其他自适应单向函数一样,应该将其调优为大约1秒来验证系统上的密码。
      •   // Create an encoder with strength 16
          BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(16);
          String result = encoder.encode("myPassword");
          assertTrue(encoder.matches("myPassword", result));
        
  • Pbkdf2PasswordEncoder:
    • Pbkdf2PasswordEncoder实现使用PBKDF2算法来散列密码。为了破解密码,PBKDF2是一种故意慢速的算法。与其他自适应单向函数一样,应该将其调优为大约1秒来验证系统上的密码。当需要FIPS认证时,该算法是一个很好的选择。
      •   // Create an encoder with all the defaults
          Pbkdf2PasswordEncoder encoder = new Pbkdf2PasswordEncoder();
          String result = encoder.encode("myPassword");
          assertTrue(encoder.matches("myPassword", result));
        
  • SCryptPasswordEncoder:
    • SCryptPasswordEncoder实现使用scrypt算法来散列密码。为了防止自定义硬件上的密码破解,scrypt是一种需要大量内存的缓慢算法。与其他自适应单向函数一样,应该将其调优为大约1秒来验证系统上的密码。
      •   // Create an encoder with all the defaults
          SCryptPasswordEncoder encoder = new SCryptPasswordEncoder();
          String result = encoder.encode("myPassword");
          assertTrue(encoder.matches("myPassword", result));
        
  • 汇总:
    •   bcrypt - BCryptPasswordEncoder (Also used for encoding)
        ldap - LdapShaPasswordEncoder
        MD4 - Md4PasswordEncoder
        MD5 - new MessageDigestPasswordEncoder("MD5")
        noop - NoOpPasswordEncoder
        pbkdf2 - Pbkdf2PasswordEncoder
        scrypt - SCryptPasswordEncoder
        SHA-1 - new MessageDigestPasswordEncoder("SHA-1")
        SHA-256 - new MessageDigestPasswordEncoder("SHA-256")
        sha256 - StandardPasswordEncoder
      
      
Core Security Filters核心安全过滤器
  • 在使用Spring安全性的web应用程序中,总是会使用一些关键的过滤器,因此我们将首先查看这些过滤器及其支持的类和接口。
  • FilterSecurityInterceptor:
    • 在讨论一般的访问控制时,我们已经简单地看到了FilterSecurityInterceptor,并且我们已经将它与名称空间一起使用,在这个名称空间中,元素被组合起来在内部配置它。
    • 现在,我们将了解如何显式地将其配置为与FilterChainProxy及其配套的filter ExceptionTranslationFilter一起使用。一个典型的配置示例如下所示:
      •   
          
          
          
              
              
              
              
          
          
        
    • FilterSecurityInterceptor负责处理HTTP资源的安全性。它需要对AuthenticationManager和AccessDecisionManager的引用。它还提供了应用于不同HTTP URL请求的配置属性。
  • ExceptionTranslationFilter:
    • ExceptionTranslationFilter位于安全筛选器堆栈中的FilterSecurityInterceptor之上。它本身不执行任何实际的安全强制,但是处理安全拦截器抛出的异常,并提供适当的HTTP响应。
    •   
        
        
        
      
        
        
        
      
        
        
        
      
    • AuthenticationEntryPoint:
      • 如果用户请求安全的HTTP资源,但它们没有经过身份验证,则调用AuthenticationEntryPoint。安全拦截器将在调用堆栈的更下方抛出适当的AuthenticationException或AccessDeniedException,触发入口点上的commence方法。
      • 它的工作是向用户显示适当的响应,以便开始身份验证。我们在这里使用的是LoginUrlAuthenticationEntryPoint,它将请求重定向到另一个URL(通常是登录页面)。实际使用的实现将取决于authenti
    • AccessDeniedHandler:
      • 如果抛出AccessDeniedException,并且用户已经通过身份验证,那么这意味着尝试了一个他们没有足够权限的操作。在这种情况下,ExceptionTranslationFilter将调用第二个策略AccessDeniedHandler。默认情况下,使用AccessDeniedHandlerImpl,它只向客户机发送一个403(禁止)响应。或者,您可以显式地配置一个实例(如上例所示)并设置一个错误页面URL,它将请求转发给[11]。这可以是一个简单的“access denied”页面,例如JSP
      • 在使用名称空间配置应用程序时,也可以提供自定义AccessDeniedHandler
  • SecurityContextPersistenceFilter:
    • 此筛选器有两个主要任务。它负责存储HTTP请求之间的SecurityContext内容,并在请求完成时清除SecurityContext。清除存储上下文的ThreadLocal是非常必要的,因为如果不这样做,线程可能会被替换到servlet容器的线程池中,而特定用户的安全上下文仍然是附加的。这个线程可能会在稍后的阶段使用,使用错误的凭据执行操作。
    •   
      
    • SecurityContextRepository: 从Spring Security 3.0开始,加载和存储安全上下文的工作现在被委托给一个单独的策略接口:
      •   public interface SecurityContextRepository {
        
          SecurityContext loadContext(HttpRequestResponseHolder requestResponseHolder);
        
          void saveContext(SecurityContext context, HttpServletRequest request,
                  HttpServletResponse response);
          }
        
      • HttpRequestResponseHolder只是传入请求和响应对象的容器,允许实现用包装器类替换它们。返回的内容将被传递到过滤器链。
  • UsernamePasswordAuthenticationFilter:
    • 它允许用户进行身份验证。此筛选器是最常用的身份验证筛选器,也是最常用的自定义[13]筛选器。它还提供了名称空间中的元素所使用的实现。
      • 使用登录页面的URL配置LoginUrlAuthenticationEntryPoint,如前所述,并将其设置在ExceptionTranslationFilter上。
      • 实现登录页面(使用JSP或MVC控制器)。
      • 在应用程序上下文中配置UsernamePasswordAuthenticationFilter的实例
      • 将筛选器bean添加到筛选器链代理中(确保注意顺序)。
    • 登录表单只包含用户名和密码输入字段,并将帖子发送到筛选器监视的URL(默认情况下为/login)。基本的过滤器配置如下:
      •   
          
          
        
  • BasicAuthenticationFilter:
    • BasicAuthenticationFilter负责处理HTTP报头中显示的基本身份验证凭据。这可以用于验证Spring remoting协议(如Hessian和Burlap)以及普通浏览器用户代理(如Firefox和Internet Explorer)发出的调用。

你可能感兴趣的:(springboot)