日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Spring security (一)架构框架-Component、Service、Filter分析

發(fā)布時間:2023/12/10 javascript 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring security (一)架构框架-Component、Service、Filter分析 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

??想要深入spring security的authentication (身份驗證)和access-control(訪問權(quán)限控制)工作流程,必須清楚spring security的主要技術(shù)點包括關(guān)鍵接口、類以及抽象類如何協(xié)同工作進(jìn)行authentication 和access-control的實現(xiàn)。

1.spring security 認(rèn)證和授權(quán)流程

常見認(rèn)證和授權(quán)流程可以分成:

  • A user is prompted to log in with a username and password (用戶用賬密碼登錄)
  • The system (successfully) verifies that the password is correct for the username(校驗密碼正確性)
  • The context information for that user is obtained (their list of roles and so on).(獲取用戶信息context,如權(quán)限)
  • A security context is established for the user(為用戶創(chuàng)建security context)
  • The user proceeds, potentially to perform some operation which is potentially protected by an access control mechanism which checks the required permissions for the operation against the current security context information.(訪問權(quán)限控制,是否具有訪問權(quán)限)
  • 1.1 spring security 認(rèn)證

    上述前三點為spring security認(rèn)證驗證環(huán)節(jié):

  • 通常通過AbstractAuthenticationProcessingFilter過濾器將賬號密碼組裝成Authentication實現(xiàn)類UsernamePasswordAuthenticationToken;
  • 將token傳遞給AuthenticationManager驗證是否有效,而AuthenticationManager通常使用ProviderManager實現(xiàn)類來檢驗;
  • AuthenticationManager認(rèn)證成功后將返回一個擁有詳細(xì)信息的Authentication object(包括權(quán)限信息,身份信息,細(xì)節(jié)信息,但密碼通常會被移除);
  • 通過SecurityContextHolder.getContext().getAuthentication().getPrincipal()將Authentication設(shè)置到security context中。
  • 1.2 spring security訪問授權(quán)

  • 通過FilterSecurityInterceptor過濾器入口進(jìn)入;
  • FilterSecurityInterceptor通過其繼承的抽象類的AbstractSecurityInterceptor.beforeInvocation(Object object)方法進(jìn)行訪問授權(quán),其中涉及了類AuthenticationManager、AccessDecisionManager、SecurityMetadataSource等。
  • 根據(jù)上述描述的過程,我們接下來主要去分析其中涉及的一下Component、Service、Filter。

    2.核心組件(Core Component )

    2.1 SecurityContextHolder

    ??SecurityContextHolder提供對SecurityContext的訪問,存儲security context(用戶信息、角色權(quán)限等),而且其具有下列儲存策略即工作模式:

  • SecurityContextHolder.MODE_THREADLOCAL(默認(rèn)):使用ThreadLocal,信息可供此線程下的所有的方法使用,一種與線程綁定的策略,此天然很適合Servlet Web應(yīng)用。

  • SecurityContextHolder.MODE_GLOBAL:使用于獨(dú)立應(yīng)用

  • SecurityContextHolder.MODE_INHERITABLETHREADLOCAL:具有相同安全標(biāo)示的線程

  • 修改SecurityContextHolder的工作模式有兩種方法 :

  • 設(shè)置一個系統(tǒng)屬性(system.properties) : spring.security.strategy;
  • 調(diào)用SecurityContextHolder靜態(tài)方法setStrategyName()
  • 在默認(rèn)ThreadLocal策略中,SecurityContextHolder為靜態(tài)方法獲取用戶信息為:

    Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();if (principal instanceof UserDetails) { String username = ((UserDetails)principal).getUsername();} else {String username = principal.toString();} 復(fù)制代碼

    但是一般不需要自身去獲取。 其中g(shù)etAuthentication()返回一個Authentication認(rèn)證主體,接下來分析Authentication、UserDetails細(xì)節(jié)。

    2.2 Authentication

    ??Spring Security使用一個Authentication對象來描述當(dāng)前用戶的相關(guān)信息,其包含用戶擁有的權(quán)限信息列表、用戶細(xì)節(jié)信息(身份信息、認(rèn)證信息)。Authentication為認(rèn)證主體在spring security中時最高級別身份/認(rèn)證的抽象,常見的實現(xiàn)類UsernamePasswordAuthenticationToken。Authentication接口源碼:

    public interface Authentication extends Principal, Serializable { //權(quán)限信息列表,默認(rèn)GrantedAuthority接口的一些實現(xiàn)類Collection<? extends GrantedAuthority> getAuthorities(); //密碼信息Object getCredentials();//細(xì)節(jié)信息,web應(yīng)用中的實現(xiàn)接口通常為 WebAuthenticationDetails,它記錄了訪問者的ip地址和sessionId的值Object getDetails();//通常返回值為UserDetails實現(xiàn)類Object getPrincipal();boolean isAuthenticated();void setAuthenticated(boolean var1) throws IllegalArgumentException; } 復(fù)制代碼

    前面兩個組件都涉及了UserDetails,以及GrantedAuthority其到底是什么呢?2.3小節(jié)分析。

    2.3 UserDetails&GrantedAuthority

    ??UserDetails提供從應(yīng)用程序的DAO或其他安全數(shù)據(jù)源構(gòu)建Authentication對象所需的信息,包含GrantedAuthority。其官方實現(xiàn)類為User,開發(fā)者可以實現(xiàn)其接口自定義UserDetails實現(xiàn)類。其接口源碼:

    public interface UserDetails extends Serializable {Collection<? extends GrantedAuthority> getAuthorities();String getPassword();String getUsername();boolean isAccountNonExpired();boolean isAccountNonLocked();boolean isCredentialsNonExpired();boolean isEnabled(); } 復(fù)制代碼

    ??UserDetails與Authentication接口功能類似,其實含義即是Authentication為用戶提交的認(rèn)證憑證(賬號密碼),UserDetails為系統(tǒng)中用戶正確認(rèn)證憑證,在UserDetailsService中的loadUserByUsername方法獲取正確的認(rèn)證憑證。 ??其中在getAuthorities()方法中獲取到GrantedAuthority列表是代表用戶訪問應(yīng)用程序權(quán)限范圍,此類權(quán)限通常是“role(角色)”,例如ROLE_ADMINISTRATOR或ROLE_HR_SUPERVISOR。GrantedAuthority接口常見的實現(xiàn)類SimpleGrantedAuthority。

    3. 核心服務(wù)類(Core Services)

    3.1 AuthenticationManager、ProviderManager以及AuthenticationProvider

    ??AuthenticationManager是認(rèn)證相關(guān)的核心接口,是認(rèn)證一切的起點。但常見的認(rèn)證流程都是AuthenticationManager實現(xiàn)類ProviderManager處理,而且ProviderManager實現(xiàn)類基于委托者模式維護(hù)AuthenticationProvider 列表用于不同的認(rèn)證方式。例如:

  • 使用賬號密碼認(rèn)證方式DaoAuthenticationProvider實現(xiàn)類(繼承了AbstractUserDetailsAuthenticationProvide抽象類),其為默認(rèn)認(rèn)證方式,進(jìn)行數(shù)據(jù)庫庫獲取認(rèn)證數(shù)據(jù)信息。
  • 游客身份登錄認(rèn)證方式AnonymousAuthenticationProvider實現(xiàn)類
  • 從cookies獲取認(rèn)證方式RememberMeAuthenticationProvider實現(xiàn)類
  • ??AuthenticationProvider為

    ProviderManager源碼分析:

    public Authentication authenticate(Authentication authentication)throws AuthenticationException {Class<? extends Authentication> toTest = authentication.getClass();AuthenticationException lastException = null;Authentication result = null;//AuthenticationProvider列表依次認(rèn)證for (AuthenticationProvider provider : getProviders()) {if (!provider.supports(toTest)) {continue;}try {//每個AuthenticationProvider進(jìn)行認(rèn)證result = provider.authenticate(authentication)if (result != null) {copyDetails(authentication, result);break;}}....catch (AuthenticationException e) {lastException = e;}}//進(jìn)行父類AuthenticationProvider進(jìn)行認(rèn)證if (result == null && parent != null) {// Allow the parent to try.try {result = parent.authenticate(authentication);}catch (AuthenticationException e) {lastException = e;}}// 如果有Authentication信息,則直接返回if (result != null) {if (eraseCredentialsAfterAuthentication&& (result instanceof CredentialsContainer)) {//清除密碼((CredentialsContainer) result).eraseCredentials();}//發(fā)布登錄成功事件eventPublisher.publishAuthenticationSuccess(result);return result;}//如果都沒認(rèn)證成功,拋出異常if (lastException == null) {lastException = new ProviderNotFoundException(messages.getMessage("ProviderManager.providerNotFound",new Object[] { toTest.getName() },"No AuthenticationProvider found for {0}"));}prepareException(lastException, authentication);throw lastException;} 復(fù)制代碼

    ??ProviderManager 中的AuthenticationProvider列表,會依照次序去認(rèn)證,默認(rèn)策略下,只需要通過一個AuthenticationProvider的認(rèn)證,即可被認(rèn)為是登錄成功,而且AuthenticationProvider認(rèn)證成功后返回一個Authentication實體,并為了安全會進(jìn)行清除密碼。如果所有認(rèn)證器都無法認(rèn)證成功,則ProviderManager 會拋出一個ProviderNotFoundException異常。

    3.2 UserDetailsService

    ??UserDetailsService接口作用是從特定的地方獲取認(rèn)證的數(shù)據(jù)源(賬號、密碼)。如何獲取到系統(tǒng)中正確的認(rèn)證憑證,通過loadUserByUsername(String username)獲取認(rèn)證信息,而且其只有一個方法:

    UserDetails loadUserByUsername(String username) throws UsernameNotFoundException; 復(fù)制代碼

    其常見的實現(xiàn)類從數(shù)據(jù)獲取的JdbcDaoImpl實現(xiàn)類,從內(nèi)存中獲取的InMemoryUserDetailsManager實現(xiàn)類,不過我們可以實現(xiàn)其接口自定義UserDetailsService實現(xiàn)類,如下:

    public class CustomUserService implements UserDetailsService {@Autowired//用戶mapperprivate UserInfoMapper userInfoMapper;@Autowired//用戶權(quán)限mapperprivate PermissionInfoMapper permissionInfoMapper;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {UserInfoDTO userInfo = userInfoMapper.getUserInfoByUserName(username);if (userInfo != null) {List<PermissionInfoDTO> permissionInfoDTOS = permissionInfoMapper.findByAdminUserId(userInfo.getId());List<GrantedAuthority> grantedAuthorityList = new ArrayList<>();//組裝權(quán)限GrantedAuthority objectfor (PermissionInfoDTO permissionInfoDTO : permissionInfoDTOS) {if (permissionInfoDTO != null && permissionInfoDTO.getPermissionName() != null) {GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(permissionInfoDTO.getPermissionName());grantedAuthorityList.add(grantedAuthority);}}//返回用戶信息return new User(userInfo.getUserName(), userInfo.getPasswaord(), grantedAuthorityList);}else {//拋出用戶不存在異常throw new UsernameNotFoundException("admin" + username + "do not exist");}} } 復(fù)制代碼

    3.3 AccessDecisionManager&SecurityMetadataSource

    ??AccessDecisionManager是由AbstractSecurityInterceptor調(diào)用,負(fù)責(zé)做出最終的訪問控制決策。

    AccessDecisionManager接口源碼:

    //訪問控制決策void decide(Authentication authentication, Object secureObject,Collection<ConfigAttribute> attrs) throws AccessDeniedException;//是否支持處理傳遞的ConfigAttributeboolean supports(ConfigAttribute attribute);//確認(rèn)class是否為AccessDecisionManagerboolean supports(Class clazz); 復(fù)制代碼

    ??SecurityMetadataSource包含著AbstractSecurityInterceptor訪問授權(quán)所需的元數(shù)據(jù)(動態(tài)url、動態(tài)授權(quán)所需的數(shù)據(jù)),在AbstractSecurityInterceptor授權(quán)模塊中結(jié)合AccessDecisionManager進(jìn)行訪問授權(quán)。其涉及了ConfigAttribute。 SecurityMetadataSource接口:

    Collection<ConfigAttribute> getAttributes(Object object)throws IllegalArgumentException;Collection<ConfigAttribute> getAllConfigAttributes();boolean supports(Class<?> clazz); 復(fù)制代碼

    我們還可以自定義SecurityMetadataSource數(shù)據(jù)源,實現(xiàn)接口FilterInvocationSecurityMetadataSource。例:

    public class MyFilterSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {public List<ConfigAttribute> getAttributes(Object object) {FilterInvocation fi = (FilterInvocation) object;String url = fi.getRequestUrl();String httpMethod = fi.getRequest().getMethod();List<ConfigAttribute> attributes = new ArrayList<ConfigAttribute>();// Lookup your database (or other source) using this information and populate the// list of attributesreturn attributes;}public Collection<ConfigAttribute> getAllConfigAttributes() {return null;}public boolean supports(Class<?> clazz) {return FilterInvocation.class.isAssignableFrom(clazz);} } 復(fù)制代碼

    3.4 PasswordEncoder

    ??為了存儲安全,一般要對密碼進(jìn)行算法加密,而spring security提供了加密PasswordEncoder接口。其實現(xiàn)類有使用BCrypt hash算法實現(xiàn)的BCryptPasswordEncoder,SCrypt hashing 算法實現(xiàn)的SCryptPasswordEncoder實現(xiàn)類,實現(xiàn)類內(nèi)部實現(xiàn)可看源碼分析。而PasswordEncoder接口只有兩個方法:

    public interface PasswordEncoder {//密碼加密String encode(CharSequence rawPassword);//密碼配對boolean matches(CharSequence rawPassword, String encodedPassword); } 復(fù)制代碼

    4 核心 Security 過濾器(Core Security Filters)

    4.1 FilterSecurityInterceptor

    ??FilterSecurityInterceptor是Spring security授權(quán)模塊入口,該類根據(jù)訪問的用戶的角色,權(quán)限授權(quán)訪問那些資源(訪問特定路徑應(yīng)該具備的權(quán)限)。
    ??FilterSecurityInterceptor封裝FilterInvocation對象進(jìn)行操作,所有的請求到了這一個filter,如果這個filter之前沒有執(zhí)行過的話,那么首先執(zhí)行其父類AbstractSecurityInterceptor提供的InterceptorStatusToken token = super.beforeInvocation(fi),在此方法中使用AuthenticationManager獲取Authentication中用戶詳情,使用ConfigAttribute封裝已定義好訪問權(quán)限詳情,并使用AccessDecisionManager.decide()方法進(jìn)行訪問權(quán)限控制。
    FilterSecurityInterceptor源碼分析:

    public void invoke(FilterInvocation fi) throws IOException, ServletException {if ((fi.getRequest() != null)&& (fi.getRequest().getAttribute(FILTER_APPLIED) != null)&& observeOncePerRequest) {fi.getChain().doFilter(fi.getRequest(), fi.getResponse());}else {// first time this request being called, so perform security checkingif (fi.getRequest() != null && observeOncePerRequest) {fi.getRequest().setAttribute(FILTER_APPLIED, Boolean.TRUE);}//回調(diào)其繼承的抽象類AbstractSecurityInterceptor的方法InterceptorStatusToken token = super.beforeInvocation(fi);try {fi.getChain().doFilter(fi.getRequest(), fi.getResponse());}finally {super.finallyInvocation(token);}super.afterInvocation(token, null);} } 復(fù)制代碼

    AbstractSecurityInterceptor源碼分析:

    protected InterceptorStatusToken beforeInvocation(Object object) {....//獲取所有訪問權(quán)限(url-role)屬性列表(已定義在數(shù)據(jù)庫或者其他地方)Collection<ConfigAttribute> attributes = this.obtainSecurityMetadataSource().getAttributes(object);....//獲取該用戶訪問信息(包括url,訪問權(quán)限)Authentication authenticated = authenticateIfRequired();// Attempt authorizationtry {//進(jìn)行授權(quán)訪問this.accessDecisionManager.decide(authenticated, object, attributes);}catch.... } 復(fù)制代碼

    4.2 UsernamePasswordAuthenticationFilter

    ??UsernamePasswordAuthenticationFilter使用username和password表單登錄使用的過濾器,也是最為常用的過濾器。其源碼:

    public Authentication attemptAuthentication(HttpServletRequest request,HttpServletResponse response) throws AuthenticationException {//獲取表單中的用戶名和密碼String username = obtainUsername(request);String password = obtainPassword(request);...username = username.trim();//組裝成username+password形式的tokenUsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);// Allow subclasses to set the "details" propertysetDetails(request, authRequest);//交給內(nèi)部的AuthenticationManager去認(rèn)證,并返回認(rèn)證信息return this.getAuthenticationManager().authenticate(authRequest); } 復(fù)制代碼

    ??其主要代碼為創(chuàng)建UsernamePasswordAuthenticationToken的Authentication實體以及調(diào)用AuthenticationManager進(jìn)行authenticate認(rèn)證,根據(jù)認(rèn)證結(jié)果執(zhí)行successfulAuthentication或者unsuccessfulAuthentication,無論成功失敗,一般的實現(xiàn)都是轉(zhuǎn)發(fā)或者重定向等處理,不再細(xì)究AuthenticationSuccessHandler和AuthenticationFailureHandle。興趣的可以研究一下其父類AbstractAuthenticationProcessingFilter過濾器。

    4.3 AnonymousAuthenticationFilter

    AnonymousAuthenticationFilter是匿名登錄過濾器,它位于常用的身份認(rèn)證過濾器(如UsernamePasswordAuthenticationFilter、BasicAuthenticationFilter、RememberMeAuthenticationFilter)之后,意味著只有在上述身份過濾器執(zhí)行完畢后,SecurityContext依舊沒有用戶信息,AnonymousAuthenticationFilter該過濾器才會有意義——基于用戶一個匿名身份。 AnonymousAuthenticationFilter源碼分析:

    public class AnonymousAuthenticationFilter extends GenericFilterBean implementsInitializingBean {...public AnonymousAuthenticationFilter(String key) {this(key, "anonymousUser", AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS"));}...public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)throws IOException, ServletException {if (SecurityContextHolder.getContext().getAuthentication() == null) {//創(chuàng)建匿名登錄Authentication的信息SecurityContextHolder.getContext().setAuthentication(createAuthentication((HttpServletRequest) req));...}chain.doFilter(req, res);}//創(chuàng)建匿名登錄Authentication的信息方法protected Authentication createAuthentication(HttpServletRequest request) {AnonymousAuthenticationToken auth = new AnonymousAuthenticationToken(key,principal, authorities);auth.setDetails(authenticationDetailsSource.buildDetails(request));return auth;} } 復(fù)制代碼

    4.4 SecurityContextPersistenceFilter

    ??SecurityContextPersistenceFilter的兩個主要作用便是request來臨時,創(chuàng)建SecurityContext安全上下文信息和request結(jié)束時清空SecurityContextHolder。源碼后續(xù)分析。

    小節(jié)總結(jié):

    . AbstractAuthenticationProcessingFilter:主要處理登錄
    . FilterSecurityInterceptor:主要處理鑒權(quán)

    總結(jié)

    ??經(jīng)過上面對核心的Component、Service、Filter分析,初步了解了Spring Security工作原理以及認(rèn)證和授權(quán)工作流程。Spring Security認(rèn)證和授權(quán)還有很多負(fù)責(zé)的過程需要深入了解,所以下次會對認(rèn)證模塊和授權(quán)模塊進(jìn)行更具體工作流程分析以及案例呈現(xiàn)。最后以上純粹個人結(jié)合博客和官方文檔總結(jié),如有錯請指出!

    轉(zhuǎn)載于:https://juejin.im/post/5d074dc1f265da1bce3dd10f

    總結(jié)

    以上是生活随笔為你收集整理的Spring security (一)架构框架-Component、Service、Filter分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。