【问题标题】:Shiro Authorization populate authorization with remote rolesShiro 授权使用远程角色填充授权
【发布时间】:2012-05-11 05:28:33
【问题描述】:

我正在使用使用 Apache Shiro 的 Tapestry-Security

我有一个处理授权和身份验证的自定义领域。从技术上讲,我们的身份验证使用远程服务进行,该服务返回用户名和一组角色。我只是将用户名传递给我的自定义 AuthenticationToken,它允许我查询我们的本地数据库并设置 SimpleAuthenticationInfo。

我不知道如何使用从我们的远程服务返回给我的角色列表来填充 AuthorizationInfo doGetAuthorizationInfo 方法。下面是我用来填充领域的代码。

登录类

//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 中的 AuthorizationInfo 方法 公共类 CustomRealm 扩展 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);
}

【问题讨论】:

  • 几周前,我写下了如何对付 Shiro 和 Guice。但是,您能否检查一下“实现领域”部分是否涵盖了您的问题 - readyareyou.blogspot.de/2012/03/guice-jersey-shiro.html ?
  • @PepperBob 感谢您的回复,在我看来,您提供给我的链接中的示例仍在使用数据库来查找用户角色。在我的场景中,角色在登录时从我们的 Web 服务列表中提供给我。我想知道如何需要将该角色列表传递到我目前丢失的 SimpleAuthorizationInfo 中。还有其他想法吗?
  • 我认为您应该能够将所有内容都粘贴到帐户接口 (shiro.apache.org/static/current/apidocs/org/apache/shiro/authc/…) 的实现中,因为它捆绑了身份验证和授权,例如。 SimpleAccount 或定制的东西。

标签: java tapestry shiro


【解决方案1】:

如果您需要身份验证和授权,扩展 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);
    }

}

【讨论】:

  • 您好 Henning,我不确定您的建议是否能回答我的问题。我在上面发布了我的 doGetAuthenticationInfo 方法。在 shiro 邮件列表上的一篇文章中,Les Hazelwood 建议您可以在身份验证期间抢先构建和缓存 AuthorizationInfo 对象,以便在登录期间只有一个被感知的“命中”。您可以通过从 doGetAuthenticationInfo 方法中调用 getAuthorizationInfo(PrincipalCollection principals) 方法来执行此操作。我不知道怎么做,你可以在这里查看shiro-user.582556.n2.nabble.com/…谢谢
  • 在那种情况下,我认为我没有完全理解这个问题。因此,您需要一步完成身份验证和授权,因为您的后端要求这样做?是的,您必须缓存属于该用户的角色,这是正确的。您遇到的具体问题是什么?是不是不知道怎么存放才能在doGetAuthorizationInfo()退货?如果是的话,为什么不在你打后端的时候把它们放在一个地图中?
  • 我刚刚发布了一个可行的解决方案。如果你看一下它,你会看到我试图完成的事情。随时提供建议。无论如何,我都不是 Shiro 专家,所以我确信还有改进的余地。谢谢亨宁。
  • @George:好的,我明白你在做什么:你想在自定义身份验证令牌上搭载你的角色,这样你就不需要在doGetAuthorizationInfo 中加载它们。就个人而言,我强烈希望在后端进行额外的往返以获取角色(或在需要它们之前缓存它们的映射)以将它们添加到令牌中,因为令牌旨在表示用户的主体和凭据,并且没有别的。
  • 我同意不应该使用主体来存储角色,但是不能选择去后端获取角色,因为它们只会在登录时发送给我一次远程登录客户端。 RemoteLoginClient 是一个与我们的人群服务通信的网络服务。您将如何将缓存映射到它们?谢谢亨宁。
【解决方案2】:

我回答了自己的问题并想发布此问题,以防其他人需要帮助或改进我的解决方案。

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

//用于处理本地认证和授权的自定义Realm。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-05-08
    • 1970-01-01
    • 1970-01-01
    • 2011-09-29
    • 2010-10-21
    • 2019-05-16
    • 1970-01-01
    • 2014-07-26
    相关资源
    最近更新 更多