Spring Security是一個可以爲基於Spring的企業應用系統提供聲明式的安全訪問控制解決方式的安全框架。它包括認證(Authentication)和受權(Authorization)兩個部分。spring
用戶認證指的是驗證某個用戶是否爲系統中的合法主體,也就是說用戶可否訪問該系統。用戶認證通常要求用戶提供用戶名和密碼。系統經過校驗用戶名和密碼來完成認證過程。用戶受權指的是驗證某個用戶是否有權限執行某個操做。安全
通常來講,系統會爲不一樣的用戶分配不一樣的角色,而每一個角色則對應一系列的權限。 spring security的主要核心功能爲認證和受權,全部的架構也是基於這兩個核心功能去實現的。架構
認證的核心組件:框架
[AuthenticationManager] 是一個接口,是認證方法的入口,定義瞭如何認證,接收一個Authentication對象做爲參數。ide
[ProviderManager] 是AuthenticationManager的一個默認實現,但它並不用來處理身份認證,而是委託給配置好的AuthenticationProvider。在ProviderManager的authenticate方法中,會輪訓成員變量List<AuthenticationProvider> providers。該providers中若是有一個AuthenticationProvider的supports函數返回true,那麼就會調用該AuthenticationProvider的authenticate函數認證,若是認證成功則整個認證過程結束。若是不成功,則繼續使用下一個合適的AuthenticationProvider進行認證,只要有一個認證成功則爲認證成功。函數
[AuthenticationProvider] 是一個接口,ProviderManager實際上把認證過程委託給了AuthenticationProvider對象(其實是一個List)來處理。AuthenticationProvider的實現類有不少,如:ui
DaoAuthenticationProvider (extends AbstractUserDetailsAuthenticationProvider):最經常使用的認證方式,經過UserDetailsService對UserDetails認證。spa
AnonymousAuthenticationProvider: 用於匿名身份認證,匿名用戶名和權限使用默認值爲anonymousUser,ROLE_ANONYMOUS線程
[Authentication] 是一個接口,它定義存儲用戶的Principal(用戶信息),Credentials(密碼),Authority(權限)等信息。它將提供這些信息給AuthenticationManager(AuthenticationProvider的各類實現類)進行驗證。驗證成功後,返回一個認證成功的Authentication的實現類的對象。Authentication的實現類也有不少,而且和AuthenticationProvider對應, 如:code
DaoAuthenticationProvider -> UsernamePasswordAuthenticationToken
AnonymousAuthenticationProvider -> AnonymousAuthenticationToken
[UserDetails] 是一個接口,定義了認證所需的必要信息,包括用戶名,密碼,權限,有效性等。在實際使用裏,(比用JPA)經過定義User實體類與DB中的User表和Role表映射實現UserDetails接口。也可使用框架的User實現類來構造User,好比使用AuthenticationManagerBuilder中的inMemoryAuthentication()方法或jdbcAuthentication()方法獲取InMemoryUserDetailsManagerConfigurer或JdbcUserDetailsManagerConfigurer對象來構造。
[SecurityContextHolder] & [SecurityContext] SecurityContextHolder是SecurityContext的存放容器,默認使用ThreadLocal存儲,意味SecurityContext在相同線程中的方法均可用。因爲SecurityContext中存放有Authentication信息,所以咱們能夠經過用這種方式在Security上下文中拿到User信息。如:
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); if (principal instanceof UserDetails) { String username = ((UserDetails)principal).getUsername(); } else { String username = principal.toString(); }
以上就是各個接口的意義及關係,認證中其實最重要的就是authenticate()方法的實現。上面也說到,AuthenticationManager把該方法委託給AuthenticationProvider來作,接下來就以AuthenticationProvider的一個最經常使用的實現類DaoAuthenticationProvider來敘述如下認證過程(具體代碼能夠從AbstractUserDetailsAuthenticationProvider.authenticate()開始看):
(1)從request中拿到username和password,存到一個UsernamePasswordAuthenticationToken(Authentication的接口實現類)對象中
(2)開始調用AbstractUserDetailsAuthenticationProvider.authenticate()方法
(3)拿到UsernamePasswordAuthenticationToken的username
(4)調用DaoAuthenticationProvider.retrieveUser(),用步驟3的username,調用UserDetailsService.loadUserByUsername()方法拿到User對象(UserDetails的接口實現類)
(5)檢查步驟4中User對象的有效性(enabled,expired,locked)
(6)調用DaoAuthenticationProvider.additionalAuthenticationChecks(),比較UsernamePasswordAuthenticationToken的password和UserDetails的password(都是encoded),一致則經過
(7)調用AbstractUserDetailsAuthenticationProvider.createSuccessAuthentication()修改和完善UsernamePasswordAuthenticationToken信息,好比從UserDetails拿到的Authorities信息
(8)返回UsernamePasswordAuthenticationToken
受權的核心組件:
[AccessDecisionManager] 是一個接口,定義了在受權時如何決策的方法,具體的實現類有3個:AffirmativeBased (一票經過) ,ConsensusBased (少數服從多數),UnanimousBased (一票反對)。其中,一票經過是默認的決策。
[AbstractAccessDecisionManager] 從這個抽象類能夠看出,決策的依據是是選票(Voter)的List集合。
[AccessDecisionVoter] 是一個接口,定義了vote方法,它的實現類也有不少,好比:
AuthenticatedVoter:好比某個用戶對某個資源的訪問是isAuthenticated()(即認證用戶),該投票就經過
RoleVoter:好比某個用戶對某個資源的訪問是hasAnyRole("xxx")或hasRole("xxx")(即有該Role的用戶),該投票就經過
咱們以AffirmativeBased爲例子看一下受權過程:
(1)調用AffirmativeBased.decide()方法
(2)輪訓成員變量List<AccessDecisionVoter<? extends Object>> decisionVoters(在父級方法AbstractAccessDecisionManager中),若是有voter中有一個是ACCESS_GRANTED(1),則受權經過。