2013-07-12 35 views
2

我正在使用Spring MVC網站並通過LDAP添加Active Directory身份驗證。該公司不希望使用AD權限來映射網站的權限,我們有一個數據庫,列出每個用戶的權限,所以我試圖連接到,獲取權限,並將它們添加到用戶的身份驗證令牌中。在AuthenticationSuccessHandler中添加授權

當我第一次開始時,我將AD用戶組的權限映射爲GrantedAuthoritiesMapper,並且我已經工作了。它看起來像這樣:

public class ActiveDirectoryGrantedAuthoritiesMapper implements GrantedAuthoritiesMapper { 

    private static final String ROLE_ADMIN = "adminUserGroup"; 

    public ActiveDirectoryGrantedAuthoritiesMapper() 
    { } 

    public Collection<? extends GrantedAuthority> mapAuthorities(
      final Collection<? extends GrantedAuthority> authorities) 
    { 

     Set<CustomAuthority> roles = EnumSet.noneOf(CustomAuthority.class); 

     for (GrantedAuthority authority : authorities) 
     { 
      if (ROLE_ADMIN.equals(authority.getAuthority())) 
      { 
       roles.add(CustomAuthority.ROLE_ADMIN); 
      } 
      //Default role for all users. 
      roles.add(CustomAuthority.ROLE_EMPLOYEE); 
     } 
     return roles; 
    } 
} 

現在我試圖將其轉換爲查詢我們的數據庫的權限。我離開GrantedAuthoritiesMapper這樣做有兩個原因。首先,我不使用LDAP的權限,爲什麼要攔截它們?還因爲我無法弄清楚如何獲取登錄GrantedAuthoritiesMapper內部的用戶名。我嘗試過使用SecurityContext,但是當我試圖撥打context.getAuthentication().getName()時,它給了我一個NullPointerException,因爲用戶還沒有完全認證。因此我轉而使用AuthenticationSuccessHandler。我試圖保持邏輯幾乎相同。我試圖用authentication.getAuthorities().add(...);將角色添加到用戶的身份驗證令牌,但我收到的錯誤是我的CustomAuthority未擴展GrantedAuthority。它沒有擴展它,但它實現了接口。我在想,如果這是因爲它是一個枚舉,所以我將它改爲一個類,我仍然得到錯誤。下面是自定義AuthenticationSuccessHandler的代碼,因爲我有現在:

public class CustomAuthoritiesMapper implements AuthenticationSuccessHandler 
{ 
    private CustomPermissionDAO permissionsDao = new CustomPermissionDAO(); 

    private static final String ROLE_ADMIN = "ADMIN_ACCOUNT"; 

    @Override 
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) 
      throws IOException, ServletException 
    { 
     List<GrantedAuthority> roles = new ArrayList<GrantedAuthority>(); 

     List<DatabasePermission> permissionsForUser = permissionsDao.getPermissionByUsername(authentication.getName()); 

     for (DatabasePermission permission : permissionsForUser) 
     { 
      if (ROLE_ADMIN.equals(permission.getTag())) 
      { 
       roles.add(new CustomAuthority("ROLE_ADMIN")); 
      } 
      //Default role for all users. 
      roles.add(new DashboardAuthority("ROLE_EMPLOYEE")); 
     } 
     for(GrantedAuthority auth : roles) 
     { 
      authentication.getAuthorities().add(auth); 
     } 
    } 
} 

我試過只是,我能想到的。一切的每一個組合我已經改變了List<GrantedAuthority>到CustomAuthority對象的名單。我嘗試使用addAll(roles)而不是添加單個的..每次我得到這種相同的錯誤的一些變化:

在類型集合中的方法add(capture#1 of?extends GrantedAuthority)不適用於參數(的GrantedAuthority)

而且CustomAuthority代碼:

public class CustomAuthority implements GrantedAuthority 
{ 
    private String name; 

    public CustomAuthority(String name) 
    { 
     this.name = name; 
    } 

    public String getAuthority() { 
     return name; 
    } 
} 

任何幫助將非常感激。

從查看「相關問題」,它看起來像authentication.getName()可能無法在這裏工作,但我想弄清楚爲什麼我無法添加我想添加到用戶權限的權限,然後才解決問題。

回答

2

這不是你原來的問題的迴應。這是一個關於如何以另一種方式完成這件事的命題。

對我來說,看起來不尋常的是,您使用AuthenticationSuccessHandler來應對AuthenticationManagerAuthenticationProviders應該完成的工作。設想兩個AuthenticationProviders,一個用於LDAP,另一個用於數據庫。問題是,如果你通過默認的AuthenticationManager合併它們,那麼只有第一個提供者會被使用。你可以準備一個自定義AuthenticationManager略有不同的邏輯:

  • 它知道兩家供應商
  • 它要求他們按照正確的順序
  • 它結合了來自兩家供應商兩種身份驗證結果爲一個全球性的結果,同時用戶來自LDAP的證書和來自數據庫的權限。

缺點:新的開發者,增加第三個身份驗證提供者可能會爲自定義AuthenticationManager感到驚訝。

優點:我認爲代碼將適合在正確的地方。

希望這會有所幫助。

1

您無法從SecurityContext獲取當前用戶名的原因是因爲它尚未填充(您仍在努力確定要包含哪些角色)。

一種選擇是使用LdapAuthenticationProvider和一個LdapAuthoritiesPopulator as described in the FAQ。下面是常見問題

public class MyAuthoritiesPopulator implements LdapAuthoritiesPopulator { 
    @Autowired 
    JdbcTemplate template; 

    public List<GrantedAuthority> getGrantedAuthorities(DirContextOperations userData, String username) { 
     List<GrantedAuthority> = template.query("select role from roles where username = ?", 
                new String[] {username}, 
                new RowMapper<GrantedAuthority>() { 
      /** 
      * We're assuming here that you're using the standard convention of using the role 
      * prefix "ROLE_" to mark attributes which are supported by Spring Security's RoleVoter. 
      */ 
      public GrantedAuthority mapRow(ResultSet rs, int rowNum) throws SQLException { 
       return new GrantedAuthorityImpl("ROLE_" + rs.getString(1)); 
      } 
     }); 
    } 
} 

這應該爲你工作,因爲它傳遞的用戶名,你的例子。使用該用戶名作爲查詢來獲取用戶的角色。

正如常見問題解答中所述,您需要使用自定義LdapAuthoritiesPopulator將其連接到LdapAuthenticationProvider。

另一種選擇是注入一個自定義的UserDetailsContextMapper。默認是LdapUserDetailsMapper,它應該讓你知道如何實現邏輯。

+0

我發現了一種在SuccessHandler中做黑客工作的方法,但這看起來似乎是正確的做法。感謝您指點我。 – JDiPierro

+0

其實..它看起來不可能使用LdapAuthoritiesPopulator與ActiveDirectoryLdapAuthenticationProvider? – JDiPierro

+0

你是對的(如果你想使用LdapAuthoritiesPopulator,我的答案指出使用LdapAuthenticationProvider)。或者,如果您想使用ActiveDirectoryLdapAuthenticationProvider,請使用UserDetailsContextMapper。 –