2012-05-01 57 views
4

我使用Tapestry,安全,它使用的Apache四郎四郎授權填充授權遠程角色

我有處理授權和認證的自定義境界。我們的認證技術上是使用遠程服務發生的,遠程服務返回一個用戶名和一組角色。我只是將用戶名傳遞給我的自定義AuthenticationToken,它允許我查詢我們的本地數據庫並設置SimpleAuthenticationInfo。

我無法弄清楚如何填充使用角色列表中AuthorizationInfo doGetAuthorizationInfo方法從我們的遠程服務還給我。以下是我用來填充領域的代碼。

Login.class

//Remote authentication service 
RemoteLoginClient client = new RemoteLoginClient(); 
RemoteSubject authenticate = client.authenticate(username, password); 

//tapestry security authentication 
Subject currentUser = SecurityUtils.getSubject(); 
CustomAuthenticationToken token = new 
    CustomAuthenticationToken(authenticate.getUsername()); 
System.out.println("roles" + authenticate.getRoles()); 

currentUser.login(token); 

customRealm 公共類CustomRealm內AuthorizationInfo方法擴展AuthorizingRealm {

protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { 
    CustomAuthenticationToken upToken = (CustomAuthenticationToken) token; 
    String email = upToken.getUsername(); 

    ApplicationUser applicationUser = (ApplicationUser) session.createCriteria(ApplicationUser.class) 
      .add(Restrictions.like("email", email + "%")) 
      .uniqueResult(); 

    if (applicationUser == null) { 
     throw new UnknownAccountException("User doesn't exist in EPRS database"); 
    } 

    return buildAuthenticationInfo(applicationUser.getId()); 
} 

protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { 
//Not sure how to populate the principle or 
//read the principle to populate the SimpleAuthorizationInfo 
    return new SimpleAuthorizationInfo(roleNames); 
} 
+0

幾個星期前,我記下了如何處理四郎和吉斯。但是,您可否檢查「實施領域」一節是否會涵蓋您的問題 - http://readyareyou.blogspot.de/2012/03/guice-jersey-shiro.html? – PepperBob

+0

@PepperBob感謝您的回覆,在我看來,您提供的鏈接中的示例仍然使用數據庫來查找用戶角色。在我的場景中,角色在登錄時從我們的Web服務列表中提供給我。我會如何將這個角色列表傳遞到SimpleAuthorizationInfo,這是我目前丟失的地方。任何額外的想法? –

+0

我認爲你應該能夠將所有東西都粘貼到Account-Interface的實現中(http://shiro.apache.org/static/current/apidocs/org/apache/shiro/authc/Account.html),因爲它捆綁了認證和授權,例如。 SimpleAccount或定製的東西。 – PepperBob

回答

6

擴展AuthorizingRealm是,如果你需要的驗證和授權,以一個良好的開端。此外,作爲PepperBob已經說過,當你在它的Account接口及其SimpleAccount實施支持身份驗證和授權在一個單一的界面,所以你並不需要太多的單獨的代碼爲doGetAuthenticationInfo()doGetAuthorizationInfo(),可以只返回來自兩種方法的相同對象。

獲取授權信息,你需要做兩件事情:

  • 獲得從作爲參數(在大多數情況下,只包含一個主反正)通過主體收集通過可用的主要getAvailablePrincipal()方法(在AuthorizingRealm中整齊地預定義)。
  • 加載您的角色並將它們傳遞到您帳戶對象上的setRoles()

...你就大功告成了。

編輯補充:

這將是存儲的角色,直到你需要他們一個非常簡單的方法。請注意,實際身份驗證在域中完成,該域依賴於RemoteLoginClient

public class MyRealm extends AuthorizingRealm { 

    private RemoteLoginClient client = ...; 

    private final Map<String, Set<String>> emailToRoles = new ConcurrentHashMap<>(); 

    @Override 
    protected AuthenticationInfo doGetAuthenticationInfo(
      AuthenticationToken token) { 
     final UsernamePasswordToken userPass = (UsernamePasswordToken) token; 

     final RemoteSubject authenticate = this.client.authenticate(
      userPass.getUserName(), userPass.getPassword()); 
     if (authenticate != null) { //assuming this means success 
      this.emailToRoles.put(userPass.getUserName(), authenticate.getRoles()); 
      return new SimpleAuthenticationInfo(...); 
     } else { 
      return null; 
     } 
    } 

    @Override 
    protected AuthorizationInfo doGetAuthorizationInfo(
      PrincipalCollection principals) { 
     final String username = (String) principals.getPrimaryPrincipal(); 
     final Set<String> roles = this.emailToRoles.get(username); 
     return new SimpleAuthorizationInfo(roles); 
    } 

} 
+0

嗨Henning,我不確定你的建議是否回答我的問題。我發佈了上面的doGetAuthenticationInfo方法。在Shiro郵件列表的帖子中,Les Hazelwood建議您可以在認證期間預先構建並緩存AuthorizationInfo對象,以便在登錄期間只有一個感知的「命中」。您可以通過在doGetAuthenticationInfo方法中調用getAuthorizationInfo(PrincipalCollection principals)方法來完成此操作。我不知道如何,你可以在這裏查看http://shiro-user.582556.n2.nabble.com/Shiro-and-LDAP-authorization-td7096956.html#a7520967謝謝 –

+0

在這種情況下,我不'我想我完全明白了這個問題。所以你需要一步完成認證和授權,因爲你的後端要求這麼做?是的,你必須緩存屬於用戶的角色,沒錯。你遇到的問題究竟是什麼?難道你不知道如何存儲它們,所以你可以在'doGetAuthorizationInfo()'中返回它們嗎?如果是的話,爲什麼不直接把它們放到地圖上呢? – Henning

+0

我剛剛發佈了一個工作解決方案。如果你想看看它,你會看到我想要完成的。隨意提供建議。我無論如何都不是Shiro專家,所以我相信還有改進的餘地。感謝Henning。 –

3

我回答了我自己的問題,並希望發佈此信息以防其他人需要幫助或可能改進我的解決方案。

Login.class方法

Object onSubmit() { 
    try { 
     //Remote Authentication 
     RemoteLoginClient client = new RemoteLoginClient(); 
     RemoteSubject authenticate = client.authenticate(formatUsername(username), password); 

     //tapestry security authentication 
     Subject currentUser = SecurityUtils.getSubject(); 
     CustomAuthenticationToken token = new CustomAuthenticationToken(authenticate.getUsername(), authenticate.getRoles()); 

     currentUser.login(token); 
    } //catch errors 
} 

//自定義令牌用於保存用戶名和其由遠程認證服務集角色。

public class CustomAuthenticationToken implements AuthenticationToken { 

private String username; 
private Set<String> roles; 

public CustomAuthenticationToken(String username, Set<String> roles) { 
    this.username = username; 
    this.roles = roles; 
} 

getters/setters 

//自定義域用於處理本地認證和授權。

public class CustomRealm extends AuthorizingRealm { 

//Hibernate Session 
private final Session session; 
public static final String EMPTY_PASSWORD = ""; 

public CustomRealm(Session session) { 
    this.session = session; 
    setCredentialsMatcher(new AllowAllCredentialsMatcher()); 
    setAuthenticationTokenClass(CustomAuthenticationToken.class); 
} 

protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { 
    CustomAuthenticationToken customToken = (CustomAuthenticationToken) token; 
    String email = customToken.getUsername(); 

    User user = (User) session.createCriteria(User.class) 
      .add(Restrictions.like("email", email+ "%")) 
      .uniqueResult(); 

    if (user == null) { 
     throw new UnknownAccountException("User doesn't exist in local database"); 
    } 

    return new SimpleAuthenticationInfo(new CustomPrincipal(user, customToken.getRoles()), EMPTY_PASSWORD, getName()); 
} 

protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { 
    return new SimpleAuthorizationInfo(((CustomPrincipal) principals.getPrimaryPrincipal()).getRoles()); 
} 

}

用於保存用戶對象和角色 公共類CustomPrincipal //定義主體{

private User user; 
private Set<String> roles; 

public CustomPrincipal() { 
} 

public CustomPrincipal(User user, Set<String> roles) { 
    this.user = user; 
    this.roles = roles; 
} 

getters/setters