Just Code

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            1 隨筆 :: 0 文章 :: 0 評論 :: 0 Trackbacks

           在Acegi中是由認證管理器確定用戶身份。一個認證管理器由借口AuthenticationManager實現。

          public ? interface ?AuthenticationManager? {
          ????
          // ~Methods?==================================================================?
          ???
          ???
          /**
          ?????*?嘗試驗證用戶身份,如果驗證成功,將返回一個含授權的完整的Authentication對象。
          ?????*?一個AuthenticationManager必須按照下面的規則處理異常:
          ?????*?如果賬號是不被允許的必須拋出DisabledException,AuthenticationManager能檢測到這個狀態。
          ?????*?如果賬號已經被鎖定必須拋出LockedException,AuthenticationManager能夠檢測被鎖定的賬號。
          ?????*?如果取到的是非法的信任狀(credential?)必須拋出BadCredentialsException。同時上述的2種異常也是可選
          ?????*?的,AuthenticationManager必須總是檢測信任狀(credential)。
          ?????*?異常必須被檢測,如果有上述的異常出現須拋出異常。
          ?????*?如果一個賬號是不被允許的或是被鎖定的,認證請求會立即被拒絕,信任狀的檢測不會發生。
          ?????*?這防止了對不被允許賬號和被鎖定的賬號的信任狀檢測。
          ?????*
          ?????*?
          @param ?authentication?the?authentication?request?object
          ?????*
          ?????*?
          @return ?a?fully?authenticated?object?including?credentials
          ?????*
          ?????*?
          @throws ?AuthenticationException?if?authentication?fails
          ????
          */

          ????
          public ?Authentication?authenticate(Authentication?authentication)
          ????????
          throws ?AuthenticationException;
          }

           Authentication?繼承了java.security.Principal,Principal實現了簡單的主體(Principal)定義。

          public ? interface ?Principal? {

          ????
          public ? boolean ?equals(Object?another);

          ????
          public ?String?toString();

          ????
          public ? int ?hashCode();

          ???
          /**
          ?????*?返回主體的名字
          ?????*
          ?????*?
          @return ?the?name?of?this?principal.
          ????
          */

          ????
          public ?String?getName();
          }

          ?

          public ? interface ?Authentication? extends ?Principal,?Serializable? {
          ????
          // ?~Methods?==================================================================

          ?
          /**
          ?????*?通過AuthenticationManager設置Principal的授權信息。
          ?????*?注意:當Class狀態為valid時,除非Value已經被可信任的AuthenticationManager設置t過,否則對Class
          ?????*?不起作用。(此句存疑?Note?that?classes?should?not?rely?on?this?value?as?being?valid?unless?it?has?
          ?????*?been?set?by?AuthenticationManager)
          ?????*?Authentication的實現類需要確保修改返回的數足不會影響Authentication?Object的狀態。(比如返回一個
          ?????*?數組的copy)。
          ?????*?
          ?????*?
          @return ?the?authorities?granted?to?the?principal,?or?null?if?authentication?has?not?been?completed
          ????
          */

          ????
          public ?GrantedAuthority[]?getAuthorities();

          ??
          /**
          ?????*?信任狀證明Principal的身份是合法的。它經常是密碼,但是也可以是任何與AuthenticationManager
          ?????*?相關的東西。
          ?????*
          ?????*?
          @return ?the?credentials?that?prove?the?identity?of?the?Principal
          ????
          */

          ????
          public ?Object?getCredentials();

          ??
          /**
          ?????*?儲存認證請求的額外信息。有可能是IP地址,證件號碼等。
          ?????*
          ?????*?
          @return ?additional?details?about?the?authentication?request,?or??null?if?not?used
          ????
          */

          ????
          public ?Object?getDetails();

          ??
          /**
          ?????*?返回一個已經通過驗證的Principal(這通常是一個用戶名)。
          ?????*
          ?????*?
          @return ?the?Principal?being?authenticated
          ????
          */

          ????
          public ?Object?getPrincipal();

          ??
          /**
          ???? * AbstractSecurityInterceptor將認證令牌交給AuthenticationManager。如果認證成功AuthenticaionManager
          ???? * 會返回一個不變的認證令牌(返回true)。
          ???? * 返回"true"會改善性能,因為不再是每一個請求都需要調用AuthenticationManager。
          ???? * 由于安全上的考慮,實現這個接口返回true的時候需要十分的小心。除非他們不再變化或者有什么途徑
          ???? * 確保屬性在最初的初始化后不再變化。
          ?????*
          ?????*?
          @return ?true?if?the?token?has?been?authenticated?and?the? AbstractSecurityInterceptor?
          ?????*????????does?not?need?to?represent?the?token?for?re-authentication?to?the AuthenticationManager
          ????
          */

          ????
          public ? boolean ?isAuthenticated();

          ??
          /**
          ???? * 詳情參閱isAuthenticate()方法
          ???? * 參數為true的情況下,如果某個實現希望拒絕一個調用,那么將拋出一個IllegalArgumentException異常。

          ?????*
          ?????*?
          @param ?isAuthenticated?true?if?the?token?should?be?trusted?(which?may?result?in?an?exception)?or
          ?????*????????false?if?the?token?should?not?be?trusted
          ?????*
          ?????*?
          @throws ?IllegalArgumentException?if?an?attempt?to?make?the?authentication?token?trusted?(by?
          ?????*????????passing?true?as?the?argument)?is?rejected?due?to?the?implementation?being?immutable?or
          ?????*????????implementing?its?own?alternative?approach?to isAuthenticated()}

          ????
          */

          ????
          public ? void ?setAuthenticated( boolean ?isAuthenticated)
          ????????
          throws ?IllegalArgumentException;
          }

           Acegi提供了一個能適應大多數情況的ProviderManager,實現了AuthenticationManager。
            ProviderManager繼承抽象類AbstractAuthenticationManager:

          public ? abstract ? class ?AbstractAuthenticationManager? implements ?AuthenticationManager? {
          ????
          // ?~Methods?==================================================================?

          ?
          /**
          ?????*?實現通過調用抽象方法doAuthentication()進行工作。
          ?????*?如果doAuthentication()方法拋出AuthenticationException異常,驗證失敗。
          ?????*
          ?????*?
          @param ?authRequest?the?authentication?request?object
          ?????*
          ?????*?
          @return ?a?fully?authenticated?object?including?credentials
          ?????*
          ?????*?
          @throws ?AuthenticationException?if?authentication?fails
          ????
          */

          ????
          public ? final ?Authentication?authenticate(Authentication?authRequest)
          ????????
          throws ?AuthenticationException? {
          ????????
          try ? {
          ????????????Authentication?authResult?
          = ?doAuthentication(authRequest);
          ????????????copyDetails(authRequest,?authResult);

          ????????????
          return ?authResult;
          ????????}
          ? catch ?(AuthenticationException?e)? {
          ????????????e.setAuthentication(authRequest);
          ????????????
          throw ?e;
          ????????}

          ????}


          ?
          /**
          ?????*?在目標Authentication的detail沒有被設置的情況下從源Authentication復制detail信息。
          ?????*
          ?????*?
          @param ?source?source?authentication
          ?????*?
          @param ?dest?the?destination?authentication?object
          ????
          */

          ????
          private ? void ?copyDetails(Authentication?source,?Authentication?dest)? {
          ????????
          if ?((dest? instanceof ?AbstractAuthenticationToken)? && ?(dest.getDetails()? == ? null ))? {
          ????????????AbstractAuthenticationToken?token?
          = ?(AbstractAuthenticationToken)?dest;

          ????????????token.setDetails(source.getDetails());
          ????????}

          ????}


          ?
          /**
          ?????*?具體的實現通過覆寫此方法提供認證服務,此方法的約束詳見AuthenticationManager的authenticate()方法
          ?????*
          ?????*?
          @param ?authentication?the?authentication?request?object
          ?????*
          ?????*?
          @return ?a?fully?authenticated?object?including?credentials
          ?????*
          ?????*?
          @throws ?AuthenticationException?if?authentication?fails
          ????
          */

          ????
          protected ? abstract ?Authentication?doAuthentication(Authentication?authentication)
          ????????
          throws ?AuthenticationException;
          }

          ?

          /**
          ??? ?*?認證請求重復的通過一組AuthenticationProviders容器進行認證。
          ??? ?*?可以通過配置ConcurrentSessionController來限制單個用戶的session數目。
          ??? ?*?AuthenticationProvider試圖得到一個非空的響應。非空的響應表明Provider已經對認證請求作出決議
          ??? ?*?而不需要嘗試其他的Provider。
          ???? *?如果provider拋出一個AuthenticationException,這個異常將會被保留直到后續的providers都被嘗試為止。
          ???? *?如果認真請求在后續的Providers中被認證成功,早先的認證異常會被忽略而成功的認證信息將被使用。
          ???? *?如果后續的Providers沒有作出一個非空的響應或一個新的AuthenticationException,那么最后接收到的
          ???? *?AuthenticationException將會被使用。
          ???? *?如果沒有一個Provider返回一個非空的響應或是表明能運行一個Authentication,那么ProviderManager將會
          ???? *?拋出一個ProviderNotFoundException異常。
          ???? *?如果一個有效的Authentication被AuthenticationProvider返回,ProviderManager將會發布一個org
          ???? *?.acegisecurity.event.authentication.AuthenticationSuccessEvent。
          ???? *?如果發現AuthenticationException,最后的AuthenticationException會發布一個適當的失敗事件。
          ???? *?默認的ProviderManager將異常和事件對應起來,我們可以通過定一個新的exceptionMappings?Properties
          ???? *?來調整對應關系。
          ???? *?在properties中,key表現的是異常的類名的完整路徑,value表現的是AbstractAuthenticationFailureEvent的
          ???? *?子類,提供子類的構造。
          ???? *
          ??? ?*?
          @see ?ConcurrentSessionController
          ?
          ??? */

          public ? class ?ProviderManager? extends ?AbstractAuthenticationManager? implements ?InitializingBean,
          ????ApplicationEventPublisherAware,?MessageSourceAware?
          {
          ????
          // ~?Static?fields/initializers?=======================================================?

          ????
          private ? static ? final ?Log?logger? = ?LogFactory.getLog(ProviderManager. class );

          ????
          // ~?Instance?fields?=============================================================?

          ????
          private ?ApplicationEventPublisher?applicationEventPublisher;
          ????
          private ?ConcurrentSessionController?sessionController? = ? new ?NullConcurrentSessionController();
          ????
          private ?List?providers;
          ????
          protected ?MessageSourceAccessor?messages? = ?AcegiMessageSource.getAccessor();
          ????
          private ?Properties?exceptionMappings;

          ????
          // ~?Methods?==================================================================?

          ????
          public ? void ?afterPropertiesSet()? throws ?Exception? {
          ????????checkIfValidList(
          this .providers);
          ????????Assert.notNull(
          this .messages,? " A?message?source?must?be?set " );

          ????????
          if ?(exceptionMappings? == ? null )? {
          ????????????exceptionMappings?
          = ? new ?Properties();
          ????????????exceptionMappings.put(AccountExpiredException.
          class .getName(),
          ????????????????AuthenticationFailureExpiredEvent.
          class .getName());
          ????????????exceptionMappings.put(AuthenticationServiceException.
          class .getName(),
          ????????????????AuthenticationFailureServiceExceptionEvent.
          class .getName());
          ????????????exceptionMappings.put(LockedException.
          class .getName(),?AuthenticationFailureLockedEvent. class .getName());
          ????????????exceptionMappings.put(CredentialsExpiredException.
          class .getName(),
          ????????????????AuthenticationFailureCredentialsExpiredEvent.
          class .getName());
          ????????????exceptionMappings.put(DisabledException.
          class .getName(),?AuthenticationFailureDisabledEvent. class .getName());
          ????????????exceptionMappings.put(BadCredentialsException.
          class .getName(),
          ????????????????AuthenticationFailureBadCredentialsEvent.
          class .getName());
          ????????????exceptionMappings.put(UsernameNotFoundException.
          class .getName(),
          ????????????????AuthenticationFailureBadCredentialsEvent.
          class .getName());
          ????????????exceptionMappings.put(ConcurrentLoginException.
          class .getName(),
          ????????????????AuthenticationFailureConcurrentLoginEvent.
          class .getName());
          ????????????exceptionMappings.put(ProviderNotFoundException.
          class .getName(),
          ????????????????AuthenticationFailureProviderNotFoundEvent.
          class .getName());
          ????????????exceptionMappings.put(ProxyUntrustedException.
          class .getName(),
          ????????????????AuthenticationFailureProxyUntrustedEvent.
          class .getName());
          ????????????doAddExtraDefaultExceptionMappings(exceptionMappings);
          ????????}

          ????}


          ????
          private ? void ?checkIfValidList(List?listToCheck)? {
          ????????
          if ?((listToCheck? == ? null )? || ?(listToCheck.size()? == ? 0 ))? {
          ????????????
          throw ? new ?IllegalArgumentException( " A?list?of?AuthenticationManagers?is?required " );
          ????????}

          ????}


          ?
          /**
          ?????*?如果在啟動期間沒有exception被IoC容器注入,這個方法提供額外的異常對應。
          ?????*
          ?????*?
          @param ?exceptionMappings?the?properties?object,?which?already?has?entries?in?it
          ????
          */

          ????
          protected ? void ?doAddExtraDefaultExceptionMappings(Properties?exceptionMappings)? {}

          ?
          /**
          ?????*?嘗試認證通過Authentication對象。
          ?????*?AuthenticationProviders組將會接連嘗試認證對象,直到其中的一個通過這個Authentication對象。
          ?????*?如果多個AuthenticationProvider通過了Authentication對象,那么只有第一個AuthenticationProvider
          ?????*?產生結果,后續的AuthenticationProvider將不會被嘗試。
          ?????*
          ?????*?
          @param ?authentication?the?authentication?request?object.
          ?????*
          ?????*?
          @return ?a?fully?authenticated?object?including?credentials.
          ?????*
          ?????*?
          @throws ?AuthenticationException?if?authentication?fails.
          ????
          */

          ????
          public ?Authentication?doAuthentication(Authentication?authentication)
          ????????
          throws ?AuthenticationException? {
          ????????Iterator?iter?
          = ?providers.iterator();

          ????????Class?toTest?
          = ?authentication.getClass();

          ????????AuthenticationException?lastException?
          = ? null ;

          ????????
          while ?(iter.hasNext())? {
          ????????????AuthenticationProvider?provider?
          = ?(AuthenticationProvider)?iter.next();

          ????????????
          if ?(provider.supports(toTest))? {
          ????????????????logger.debug(
          " Authentication?attempt?using? " ? + ?provider.getClass().getName());

          ????????????????Authentication?result?
          = ? null ;

          ????????????????
          try ? {
          ????????????????????result?
          = ?provider.authenticate(authentication);
          ????????????????????sessionController.checkAuthenticationAllowed(result);
          ????????????????}
          ? catch ?(AuthenticationException?ae)? {
          ????????????????????lastException?
          = ?ae;
          ????????????????????result?
          = ? null ;
          ????????????????}


          ????????????????
          if ?(result? != ? null )? {
          ????????????????????sessionController.registerSuccessfulAuthentication(result);
          ????????????????????applicationEventPublisher.publishEvent(
          new ?AuthenticationSuccessEvent(result));

          ????????????????????
          return ?result;
          ????????????????}

          ????????????}

          ????????}


          ????????
          if ?(lastException? == ? null )? {
          ????????????lastException?
          = ? new ?ProviderNotFoundException(messages.getMessage( " ProviderManager.providerNotFound " ,
          ????????????????????????
          new ?Object[]? {toTest.getName()} ,? " No?AuthenticationProvider?found?for?{0} " ));
          ????????}


          ????????
          // ?Publish?the?event
          ????????String?className? = ?exceptionMappings.getProperty(lastException.getClass().getName());
          ????????AbstractAuthenticationEvent?event?
          = ? null ;

          ????????
          if ?(className? != ? null )? {
          ????????????
          try ? {
          ????????????????Class?clazz?
          = ?getClass().getClassLoader().loadClass(className);
          ????????????????Constructor?constructor?
          = ?clazz.getConstructor( new ?Class[]? {
          ????????????????????????????Authentication.
          class ,?AuthenticationException. class
          ????????????????????????}
          );
          ????????????????Object?obj?
          = ?constructor.newInstance( new ?Object[]? {authentication,?lastException} );
          ????????????????Assert.isInstanceOf(AbstractAuthenticationEvent.
          class ,?obj,? " Must?be?an?AbstractAuthenticationEvent " );
          ????????????????event?
          = ?(AbstractAuthenticationEvent)?obj;
          ????????????}
          ? catch ?(ClassNotFoundException?ignored)? {}
          ????????????
          catch ?(NoSuchMethodException?ignored)? {}
          ????????????
          catch ?(IllegalAccessException?ignored)? {}
          ????????????
          catch ?(InstantiationException?ignored)? {}
          ????????????
          catch ?(InvocationTargetException?ignored)? {}
          ????????}


          ????????
          if ?(event? != ? null )? {
          ????????????applicationEventPublisher.publishEvent(event);
          ????????}
          ? else ? {
          ????????????
          if ?(logger.isDebugEnabled())? {
          ????????????????logger.debug(
          " No?event?was?found?for?the?exception? " ? + ?lastException.getClass().getName());
          ????????????}

          ????????}


          ????????
          // ?Throw?the?exception
          ???????? throw ?lastException;
          ????}


          ????
          public ?List?getProviders()? {
          ????????
          return ? this .providers;
          ????}


          ?
          /**
          ?????*?返回設定的ConcurrentSessionController對象,如果對象沒有被設置則返回一個
          ?????*?NullConcurrentSessionController(默認初始化的對象)
          ?????*
          ?????*?
          @return ?ConcurrentSessionController?instance
          ????
          */

          ????
          public ?ConcurrentSessionController?getSessionController()? {
          ????????
          return ?sessionController;
          ????}


          ????
          public ? void ?setApplicationEventPublisher(ApplicationEventPublisher?applicationEventPublisher)? {
          ????????
          this .applicationEventPublisher? = ?applicationEventPublisher;
          ????}


          ????
          public ? void ?setMessageSource(MessageSource?messageSource)? {
          ????????
          this .messages? = ? new ?MessageSourceAccessor(messageSource);
          ????}


          ?
          /**
          ?????*?設置AuthenticationProvider對象
          ?????*?
          ?????*?
          @param ?newList
          ?????*
          ?????*?
          @throws ?IllegalArgumentException?DOCUMENT?ME!
          ????
          */

          ????
          public ? void ?setProviders(List?newList)? {
          ????????checkIfValidList(newList);

          ????????Iterator?iter?
          = ?newList.iterator();

          ????????
          while ?(iter.hasNext())? {
          ????????????Object?currentObject?
          = ? null ;

          ????????????
          try ? {
          ????????????????currentObject?
          = ?iter.next();

          ????????????????AuthenticationProvider?attemptToCast?
          = ?(AuthenticationProvider)?currentObject;
          ????????????}
          ? catch ?(ClassCastException?cce)? {
          ????????????????
          throw ? new ?IllegalArgumentException( " AuthenticationProvider? " ? + ?currentObject.getClass().getName()
          ????????????????????
          + ? " ?must?implement?AuthenticationProvider " );
          ????????????}

          ????????}


          ????????
          this .providers? = ?newList;
          ????}


          ?
          /**
          ?????*?設置ConcurrentSessionController來限制用戶的session數量。
          ?????*?默認設置為NullConcurrentSessionController
          ?????*
          ?????*?
          @param ?sessionController?ConcurrentSessionController
          ????
          */

          ????
          public ? void ?setSessionController(ConcurrentSessionController?sessionController)? {
          ????????
          this .sessionController? = ?sessionController;
          ????}

          }



            AuthenticationManager不依靠自己實現身份驗證,而是通過Iterator逐個遍歷AuthenticationProvider的子類集合(如果使用Spring的話子類類型由配置文件注入),直到某個Provider成功驗證Authentication。

            Acegi提供的Provider實現包括:
            AuthByAdapterProvider、CasAuthenticationProvider、DaoAuthenticationProvider、JaasAuthenticationProvider、PasswordDaoAuthenticationProvider、RemoteAuthenticationProvider、RunAsImplAuthenticationProvider、TestingAuthenticationProvider。

            下面只分析DaoAuthenticationProvider的相關類,按照AuthenticationProvider-->AbstractUserDetailsAuthenticationProvider-->DaoAuthenticationProvider的順序展開。

          /**
          ???? *?這個類處理一個Authenticaon類的具體實現
          ?
          ??? */

          public ? interface ?AuthenticationProvider? {
          ????
          // ~?Methods?==================================================================

          ?
          /**
          ?????*?和AuthenticationManager的同名方法實現同樣的功能,詳見AuthenticationManager
          ?????*
          ?????*?
          @param ?authentication?the?authentication?request?object.
          ?????*
          ?????*?
          @return ?a?fully?authenticated?object?including?credentials.?May?return?null?if?the
          ?????*?????????AuthenticationProvider?is?unable?to?support?authentication?of?the?passed
          ?????*?????????Authentication?object.?In?such?a?case,?the?next?AuthenticationProvider?that
          ?????*?????????supports?the?presented?Authentication?class?will?be?tried.
          ?????*
          ?????*?
          @throws ?AuthenticationException?if?authentication?fails.
          ????
          */

          ????
          public ?Authentication?authenticate(Authentication?authentication)
          ????????
          throws ?AuthenticationException;

          ??
          /**
          ?????*?如果這個AuthenticationProvider支持通過Authentication對象,則返回True。
          ?????*?返回True并不意味著AuthenticationProvider能認證當前的Authenctication。
          ?????*?他只是簡單的聲明支持通過認證。AuthenticationProvider仍舊能夠通過authenticate()方法返回null,
          ?????*?使其它的Provider能夠嘗試認證這個Authentication。(存疑)
          ?????*?選擇哪一個AuthenticatonProvider履行鑒定是由ProviderManager在運行時管理的。
          ?????*
          ?????*?
          @param ?authentication?DOCUMENT?ME!
          ?????*
          ?????*?
          @return ?true?if?the?implementation?can?more?closely?evaluate?the?Authentication?class
          ?????*?????????presented
          ????
          */

          ????
          public ? boolean ?supports(Class?authentication);
          }


          /**
          ???? *?Authentication的基類,允許子類覆寫他的方法以及使用UserDetails對象
          ???? *?這個類被設計用來對UsernamePasswordAuthenticationToken的認證請求作出相應。
          ???? *?在成功驗證的基礎上,UsernamePasswordAuthenticationToken會被構造同時返回給調用者。
          ???? *?令牌可以是用戶名的String形式也可以是由認證庫中取得的UserDetails對象。
          ???? *?如果適配器容器正在被使用,而又期望得到用戶名的情況下,使用String類型是適當的。?
          ???? *?如果需要訪問額外的用戶信息,例如電子郵件地址、用戶導向的名字等等,那么使用UserDetail是恰
          ???? *?當的。UserDetail提供了更靈活的訪問,所以通常情況下我們返回一個UserDetail而并不推薦使用適配
          ???? *?器容器。如果想要覆寫默認的方式,將setForcePrincipalAsString置true即可。
          ???? *?UserDetails通過緩存放置在UserCache中。這確保了如果后續的請求在用戶名相同的情況下可以不通過
          ???? *?UserDetailsService查詢。需要指出的是:如果用戶無意間輸入了錯誤的密碼,UserDetailService去查詢
          ??? ?*?出用戶最后一次輸入的密碼并與之比較。
          ?
          ??? */

          public ? abstract ? class ?AbstractUserDetailsAuthenticationProvider? implements ?AuthenticationProvider,?InitializingBean,
          ????MessageSourceAware?
          {
          ????
          // ~?Instance?fields?=============================================================

          ????
          protected ?MessageSourceAccessor?messages? = ?AcegiMessageSource.getAccessor();
          ????
          private ?UserCache?userCache? = ? new ?NullUserCache();
          ????
          private ? boolean ?forcePrincipalAsString? = ? false ;
          ????
          protected ? boolean ?hideUserNotFoundExceptions? = ? true ;

          ????
          // ~?Methods?==================================================================

          ?
          /**
          ?????*?允許子類對認證請求返回或緩存的UserDetails提供額外的校驗。
          ?????*?通常情況下子類至少會對Authentication的getCredentials()方法和UserDetails的getPassword()方法進行
          ?????*?比照。
          ?????*?如果定制的邏輯需要比照額外的UserDetail屬性或者UsernamePasswordAuthenticationToken,也應該在
          ?????*?這個方法中定制。
          ?????*
          ?????*?
          @param ?userDetails?as?retrieved?from?the??#retrieveUser(String,?
          ?????*????????UsernamePasswordAuthenticationToken)}?or UserCache
          ?????*?
          @param ?authentication?the?current?request?that?needs?to?be?authenticated
          ?????*
          ?????*?
          @throws ?AuthenticationException?AuthenticationException?if?the?credentials?could?not?be?validated?
          ?????*????????(generally?a ?BadCredentialsException?an?AuthenticationServiceException)
          ????
          */

          ????
          protected ? abstract ? void ?additionalAuthenticationChecks(UserDetails?userDetails,
          ????????UsernamePasswordAuthenticationToken?authentication)
          ????????
          throws ?AuthenticationException;

          ????
          public ? final ? void ?afterPropertiesSet()? throws ?Exception? {
          ????????Assert.notNull(
          this .userCache,? " A?user?cache?must?be?set " );
          ????????Assert.notNull(
          this .messages,? " A?message?source?must?be?set " );
          ????????doAfterPropertiesSet();
          ????}


          ????
          public ?Authentication?authenticate(Authentication?authentication)
          ????????
          throws ?AuthenticationException? {
          ????????Assert.isInstanceOf(UsernamePasswordAuthenticationToken.
          class ,?authentication,
          ????????????messages.getMessage(
          " AbstractUserDetailsAuthenticationProvider.onlySupports " ,
          ????????????????
          " Only?UsernamePasswordAuthenticationToken?is?supported " ));

          ????????
          // ?Determine?username
          ????????String?username? = ?(authentication.getPrincipal()? == ? null )? ? ? " NONE_PROVIDED " ?:?authentication.getName();

          ????????
          boolean ?cacheWasUsed? = ? true ;
          ????????UserDetails?user?
          = ? this .userCache.getUserFromCache(username);

          ????????
          if ?(user? == ? null )? {
          ????????????cacheWasUsed?
          = ? false ;

          ????????????
          try ? {
          ????????????????user?
          = ?retrieveUser(username,?(UsernamePasswordAuthenticationToken)?authentication);
          ????????????}
          ? catch ?(UsernameNotFoundException?notFound)? {
          ????????????????
          if ?(hideUserNotFoundExceptions)? {
          ????????????????????
          throw ? new ?BadCredentialsException(messages.getMessage(
          ????????????????????????????
          " AbstractUserDetailsAuthenticationProvider.badCredentials " ,? " Bad?credentials " ));
          ????????????????}
          ? else ? {
          ????????????????????
          throw ?notFound;
          ????????????????}

          ????????????}


          ????????????Assert.notNull(user,?
          " retrieveUser?returned?null?-?a?violation?of?the?interface?contract " );
          ????????}


          ????????
          if ?( ! user.isAccountNonLocked())? {
          ????????????
          throw ? new ?LockedException(messages.getMessage( " AbstractUserDetailsAuthenticationProvider.locked " ,
          ????????????????????
          " User?account?is?locked " ));
          ????????}


          ????????
          if ?( ! user.isEnabled())? {
          ????????????
          throw ? new ?DisabledException(messages.getMessage( " AbstractUserDetailsAuthenticationProvider.disabled " ,
          ????????????????????
          " User?is?disabled " ));
          ????????}


          ????????
          if ?( ! user.isAccountNonExpired())? {
          ????????????
          throw ? new ?AccountExpiredException(messages.getMessage( " AbstractUserDetailsAuthenticationProvider.expired " ,
          ????????????????????
          " User?account?has?expired " ));
          ????????}


          ????????
          // ?This?check?must?come?here,?as?we?don't?want?to?tell?users
          ????????
          // ?about?account?status?unless?they?presented?the?correct?credentials
          ???????? try ? {
          ????????????additionalAuthenticationChecks(user,?(UsernamePasswordAuthenticationToken)?authentication);
          ????????}
          ? catch ?(AuthenticationException?exception)? {
          ????????????
          // ?There?was?a?problem,?so?try?again?after?checking?we're?using?latest?data
          ????????????cacheWasUsed? = ? false ;
          ????????????user?
          = ?retrieveUser(username,?(UsernamePasswordAuthenticationToken)?authentication);
          ????????????additionalAuthenticationChecks(user,?(UsernamePasswordAuthenticationToken)?authentication);
          ????????}


          ????????
          if ?( ! user.isCredentialsNonExpired())? {
          ????????????
          throw ? new ?CredentialsExpiredException(messages.getMessage(
          ????????????????????
          " AbstractUserDetailsAuthenticationProvider.credentialsExpired " ,? " User?credentials?have?expired " ));
          ????????}


          ????????
          if ?( ! cacheWasUsed)? {
          ????????????
          this .userCache.putUserInCache(user);
          ????????}


          ????????Object?principalToReturn?
          = ?user;

          ????????
          if ?(forcePrincipalAsString)? {
          ????????????principalToReturn?
          = ?user.getUsername();
          ????????}


          ????????
          return ?createSuccessAuthentication(principalToReturn,?authentication,?user);
          ????}


          ?
          /**
          ?????*?構建一個成功的Authentication對象。使用的保護類型所以子類可以覆寫本方法。
          ?????*?子類往往會將用戶提供的原始信任狀(未經修改以及密碼未被解密)儲存在返回的Authentication
          ?????*?對象中。
          ?????*
          ?????*?
          @param ?principal?that?should?be?the?principal?in?the?returned?object?(defined?by?the?
          ?????*????????#isForcePrincipalAsString()?method)
          ?????*?
          @param ?authentication?that?was?presented?to?the?provider?for?validation
          ?????*?
          @param ?user?that?was?loaded?by?the?implementation
          ?????*
          ?????*?
          @return ?the?successful?authentication?token
          ????
          */

          ????
          protected ?Authentication?createSuccessAuthentication(Object?principal,?Authentication?authentication,
          ????????UserDetails?user)?
          {
          ????????
          // ?Ensure?we?return?the?original?credentials?the?user?supplied,
          ????????
          // ?so?subsequent?attempts?are?successful?even?with?encoded?passwords.
          ????????
          // ?Also?ensure?we?return?the?original?getDetails(),?so?that?future
          ????????
          // ?authentication?events?after?cache?expiry?contain?the?details
          ????????UsernamePasswordAuthenticationToken?result? = ? new ?UsernamePasswordAuthenticationToken(principal,
          ????????????????authentication.getCredentials(),?user.getAuthorities());
          ????????result.setDetails(authentication.getDetails());

          ????????
          return ?result;
          ????}


          ????
          protected ? void ?doAfterPropertiesSet()? throws ?Exception? {}

          ????
          public ?UserCache?getUserCache()? {
          ????????
          return ?userCache;
          ????}


          ????
          public ? boolean ?isForcePrincipalAsString()? {
          ????????
          return ?forcePrincipalAsString;
          ????}


          ????
          public ? boolean ?isHideUserNotFoundExceptions()? {
          ????????
          return ?hideUserNotFoundExceptions;
          ????}


          ?
          /**
          ?????*?允許子類由定義的實現位置獲取UserDetails,如果呈上的信任狀是非法的可以有選擇的拋出
          ?????*?AuthenticationExcepton異常(在有必要將用戶與資源綁定來獲取或產生UserDetail的情況下,這種處理
          ?????*?方式是十分有效的)。
          ?????*?子類沒有必要去實現任何的緩存,因為AbstractUserDetailsAuthenticationProvider在默認的情況下
          ?????*?將會緩存UserDetails。
          ?????*?UserDetails的緩存是十分復雜的,這意味著后續的認證請求即使是從緩存中得到回復也仍舊要進行
          ?????*?信任狀的校驗,即使信任狀的校驗被基類在這個方法中用binding-based策略實現。
          ?????*?因此在子類禁用緩存(如果想要保證這個方法是唯一能夠進行認證的方法,沒有UserDetails將會
          ?????*?被緩存)或是確認子類實現additionalAuthenticationChecks()方法來進行被緩存的UserDetails
          ?????*?對象的信任狀和后續的認證請求的比照的情況下它是十分重要的。
          ?????*?在大多數情況下子類不必要在這個方法中實現信任狀的校驗,取而代之的是在
          ?????*?additionalAuthenticationChecks()方法中實現。這樣代碼不用在2個方法中都實現信任狀的校驗。
          ?????*
          ?????*?
          @param ?username?The?username?to?retrieve
          ?????*?
          @param ?authentication?The?authentication?request,?which?subclasses?may?need?to?perform?a?binding-based
          ?????*????????retrieval?of?the?UserDetails
          ?????*
          ?????*?
          @return ?the?user?information?(never?null?-?instead?an?exception?should?the?thrown)
          ?????*
          ?????*?
          @throws ?AuthenticationException?if?the?credentials?could?not?be?validated?(generally?a
          ?????*?????????BadCredentialsExceptionan?,an?AuthenticationServiceException?or
          ?????*?????????UsernameNotFoundException)
          ????
          */

          ????
          protected ? abstract ?UserDetails?retrieveUser(String?username,?UsernamePasswordAuthenticationToken?authentication)
          ????????
          throws ?AuthenticationException;

          ????
          public ? void ?setForcePrincipalAsString( boolean ?forcePrincipalAsString)? {
          ????????
          this .forcePrincipalAsString? = ?forcePrincipalAsString;
          ????}


          ?
          /**
          ?????*?在通常情況,如果用戶名沒有找到或是密碼錯誤AbstractUserDetailsAuthenticationProvider將會
          ?????*?拋出一個BadCredentialsException異常。設置這個屬性為false的話,程序將會拋出
          ?????*?UsernameNotFoundException來取代BadCredentialsException異常。
          ?????*?需要注意的是:我們認為這不如拋出BadCredentialsException來的可靠。
          ?????*
          ?????*?
          @param ?hideUserNotFoundExceptions?set?to?false?if?you?wish?UsernameNotFoundExceptions
          ?????*????????to?be?thrown?instead?of?the?non-specific?BadCredentialsException?(defaults?to
          ?????*????????true)
          ????
          */

          ????
          public ? void ?setHideUserNotFoundExceptions( boolean ?hideUserNotFoundExceptions)? {
          ????????
          this .hideUserNotFoundExceptions? = ?hideUserNotFoundExceptions;
          ????}


          ????
          public ? void ?setMessageSource(MessageSource?messageSource)? {
          ????????
          this .messages? = ? new ?MessageSourceAccessor(messageSource);
          ????}


          ????
          public ? void ?setUserCache(UserCache?userCache)? {
          ????????
          this .userCache? = ?userCache;
          ????}


          ????
          public ? boolean ?supports(Class?authentication)? {
          ????????
          return ?(UsernamePasswordAuthenticationToken. class .isAssignableFrom(authentication));
          ????}

          }

          ?

          /**
          ???? *?AuthenticationProvider的具體實現,由UserDetailsService獲取用戶的詳細信息。
          ???? *
          ?
          ??? */

          public ? class ?DaoAuthenticationProvider? extends ?AbstractUserDetailsAuthenticationProvider? {
          ????
          // ~?Instance?fields?=============================================================

          ????
          private ?PasswordEncoder?passwordEncoder? = ? new ?PlaintextPasswordEncoder();
          ????
          private ?SaltSource?saltSource;
          ????
          private ?UserDetailsService?userDetailsService;

          ????
          // ~?Methods?==================================================================

          ????
          protected ? void ?additionalAuthenticationChecks(UserDetails?userDetails,
          ????????UsernamePasswordAuthenticationToken?authentication)
          ????????
          throws ?AuthenticationException? {
          ????????Object?salt?
          = ? null ;

          ????????
          if ?( this .saltSource? != ? null )? {
          ????????????salt?
          = ? this .saltSource.getSalt(userDetails);
          ????????}


          ????????
          if ?( ! passwordEncoder.isPasswordValid(userDetails.getPassword(),?authentication.getCredentials().toString(),?salt))? {
          ????????????
          throw ? new ?BadCredentialsException(messages.getMessage(
          ????????????????????
          " AbstractUserDetailsAuthenticationProvider.badCredentials " ,? " Bad?credentials " ),?userDetails);
          ????????}

          ????}


          ????
          protected ? void ?doAfterPropertiesSet()? throws ?Exception? {
          ????????Assert.notNull(
          this .userDetailsService,? " An?Authentication?DAO?must?be?set " );
          ????}


          ????
          public ?PasswordEncoder?getPasswordEncoder()? {
          ????????
          return ?passwordEncoder;
          ????}


          ????
          public ?SaltSource?getSaltSource()? {
          ????????
          return ?saltSource;
          ????}


          ????
          public ?UserDetailsService?getUserDetailsService()? {
          ????????
          return ?userDetailsService;
          ????}


          ????
          protected ? final ?UserDetails?retrieveUser(String?username,?UsernamePasswordAuthenticationToken?authentication)
          ????????
          throws ?AuthenticationException? {
          ????????UserDetails?loadedUser;

          ????????
          try ? {
          ????????????loadedUser?
          = ? this .getUserDetailsService().loadUserByUsername(username);
          ????????}
          ? catch ?(DataAccessException?repositoryProblem)? {
          ????????????
          throw ? new ?AuthenticationServiceException(repositoryProblem.getMessage(),?repositoryProblem);
          ????????}


          ????????
          if ?(loadedUser? == ? null )? {
          ????????????
          throw ? new ?AuthenticationServiceException(
          ????????????????
          " AuthenticationDao?returned?null,?which?is?an?interface?contract?violation " );
          ????????}


          ????????
          return ?loadedUser;
          ????}


          ?
          /**
          ?????*?設置密碼解密實例來進行密碼的解密校驗。如果沒有設置,將會使用PlaintextPosswordEncoder
          ?????*?作為默認設置。
          ?????*
          ?????*?
          @param ?passwordEncoder?The?passwordEncoder?to?use
          ????
          */

          ????
          public ? void ?setPasswordEncoder(PasswordEncoder?passwordEncoder)? {
          ????????
          this .passwordEncoder? = ?passwordEncoder;
          ????}


          ?
          /**
          ?????*?(source?of?salts翻譯不來)此方法解迷密碼的時候使用。
          ?????*?null是一個合法得值,這表明DaoAuthenticationProvider會把null返回給PasswordEncoder。
          ?????*
          ?????*?
          @param ?saltSource?to?use?when?attempting?to?decode?passwords?via?the?PasswordEncoder
          ????
          */

          ????
          public ? void ?setSaltSource(SaltSource?saltSource)? {
          ????????
          this .saltSource? = ?saltSource;
          ????}


          ????
          public ? void ?setUserDetailsService(UserDetailsService?authenticationDao)? {
          ????????
          this .userDetailsService? = ?authenticationDao;
          ????}

          }


          ?

          posted on 2006-07-25 16:13 dada 閱讀(2047) 評論(0)  編輯  收藏 所屬分類: Acegi

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 丹棱县| 绍兴县| 贺州市| 苏州市| 金坛市| 富顺县| 凤阳县| 冷水江市| 讷河市| 德江县| 淳安县| 芜湖市| 望江县| 成安县| 柏乡县| 凉山| 长兴县| 读书| 汨罗市| 南乐县| 庄河市| 隆德县| 本溪| 比如县| 五常市| 湟中县| 邵阳县| 阿坝| 东台市| 抚宁县| 罗江县| 贺兰县| 上虞市| 合川市| 安塞县| 鹿泉市| 抚顺县| 赞皇县| 库伦旗| 保德县| 屏东市|