1. 程式人生 > >Spring security 基本感知

Spring security 基本感知

流程

1.接收請求

1、HTTP基本身份驗證請求通過過濾器鏈直到它到達BasicAuthenticationFilter。

2、HTTP摘要式身份驗證請求通過過濾器鏈,直到它到達DigestAuthenticationFilter。

3、登入表單提交請求(登入表單身份驗證請求)通過過濾器鏈直到它到達UsernamePasswordAuthenticationFilter。

4、x509身份驗證請求通過過濾器鏈直到它到達X509AuthenticationFilter等...

2.根據使用者憑據建立AuthenticationToken

相關的AuthenticationFilter收到身份驗證請求,會從收到的請求中提取使用者名稱和密碼(大多數身份驗證機制都需要使用者名稱和密碼)。 之後,它會根據提取的使用者憑據建立一個Authentication物件。 如果提取的憑據是使用者名稱和密碼,則將使用提取/找到的使用者名稱和密碼建立UsernamePasswordAuthenticationToken。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.security.core;

import java.io.Serializable;
import java.security.Principal;
import java.util.Collection;

public interface Authentication extends Principal, Serializable {

    Collection<? extends GrantedAuthority> getAuthorities();

    Object getCredentials();

    Object getDetails();

    Object getPrincipal();

    boolean isAuthenticated();

    void setAuthenticated(boolean var1) throws IllegalArgumentException;
}

3.建立的AuthenticationToken委派給AuthenticationManagager

它將用於呼叫AuthenticationManager的authenticate方法。 AuthenticationManager只是一個介面,實際的實現是ProviderManager。

public interface AuthenticationManager {
    // 核心
    Authentication authenticate(Authentication authentication)throws AuthenticationException;

}

ProviderManager有一個配置的AuthenticationProvider列表,應該用於驗證使用者請求。 ProviderManager將遍歷每個提供的AuthenticationProvider,並嘗試根據傳遞的Authentication Object對使用者進行身份驗證(例如: - UsernamePasswordAuthenticationToken)

4.嘗試使用AuthenticationProvider列表進行身份驗證

// 自定義驗證器時需要實現
public interface AuthenticationProvider {
    // 驗證規則
    Authentication authenticate(Authentication var1) throws AuthenticationException;
    // 支援的Authentication型別 
    boolean supports(Class<?> var1);
}

以下是框架附帶的一些現有身份驗證程式:

  • CasAuthenticationProvider
  • JaasAuthenticationProvider
  • DaoAuthenticationProvider
  • OpenIDAuthenticationProvider
  • RememberMeAuthenticationProvider
  • LdapAuthenticationProvider

5. 驗證資料來源:UserDetailsService

public interface UserDetailsService {
    // 根據使用者名稱獲取使用者資訊,返回封裝成UserDetail或實現返回
    UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;

}

6、7. UserDetails 介面和 User 實現?

UserDetailsService將根據使用者名稱檢索UserDetails(實際實現是User)。

public interface UserDetails extends Serializable {
    Collection<? extends GrantedAuthority> getAuthorities();

    String getPassword();

    String getUsername();

    boolean isAccountNonExpired();

    boolean isAccountNonLocked();

    boolean isCredentialsNonExpired();

    boolean isEnabled();
}

User實現:org.springframework.security.core.userdetails.User

8.返回Authentication 或者丟擲 AuthenticationException?

如果使用者成功通過身份驗證,則將返回完全填充的Authentication物件。 否則將丟擲AuthenticationException。

如果丟擲任何AuthenticationException,那將由支援身份驗證機制的已配置AuthenticationEntryPoint處理。

9.驗證完成!

AuthenticationManager將獲取的完全填充的Authentication物件返回到相關的Authentication 過濾器。

然後,相關的AuthenticationFilter會將獲取的身份驗證物件儲存在SecurityContext中,以供將來過濾器使用。 (用於授權過濾器)

SecurityContextHolder.getContext().setAuthentication(authentication);

元件

SecurityContextHolder

SecurityContextHolder使用ThreadLocal來儲存這些詳細資訊,這意味著安全上下文始終可用於同一執行執行緒中的方法,即使安全上下文未作為這些方法的引數顯式傳遞

  • 配置:
    • SecurityContextHolder.MODE_GLOBAL策略:獨立應用程式,全域性共享使用者資訊
    • SecurityContextHolder.MODE_INHERITABLETHREADLOCAL:安全執行緒生成的執行緒也採用相同的安全標識
// 從SecurityContextHolder中獲取使用者身份資訊
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();

if (principal instanceof UserDetails) {
    String username = ((UserDetails)principal).getUsername();
} else {
    String username = principal.toString();
}

UserDetailsService

資料來源:UserDetails loadUserByUsername(String username) throws UsernameNotFoundException; 校驗實現:AuthenticationProvider

GrantedAuthority

Authentication提供的另一個重要方法是getAuthorities()。 此方法提供GrantedAuthority物件的陣列。GrantedAuthority是授予主體的許可權。 這些許可權通常是“角色”,例如ROLE_ADMINISTRATOR或ROLE_HR_SUPERVISOR