Shiro授权使用远程角色填充授权

时间:2012-05-01 17:50:12

标签: java tapestry shiro

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

我有一个处理授权和身份验证的自定义域。我们的身份验证在技术上使用远程服务进行,该服务返回用户名和一组角色。我只是将用户名传递给我的自定义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中的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);
}

2 个答案:

答案 0 :(得分: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);
    }

}

答案 1 :(得分: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

// Custom 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