【问题标题】:Using Shiro with OAuth and JWT将 Shiro 与 OAuth 和 JWT 一起使用
【发布时间】:2018-06-17 01:00:12
【问题描述】:

我们在我们的应用程序中使用 shiro,并且会话保存在数据库中以进行扩展。而且我们有自己的帐户数据库,到目前为止一切顺利。

这是核心安全组件:

  1. 数据库领域

通过UsernameAndPasswordToken验证用户和数据库中的密码,从数据库中检索权限。

  1. DatabaseSessionDao

扩展CachingSessionDAO,用于从数据库中创建、读取、删除会话。

  1. DefaultWebSessionManager

Shiro 内置组件。

现在我们要做两种改进:

  1. 集成 OAuth 登录

例如,用户应该能够通过GoogleFacebook 或他们在我们的应用程序中注册的帐户登录。

然后我想知道我们如何重新使用现有的安全组件,如DatabaseRealm,因为领域将检查在 OAuth 上下文中不可用的AuthenticationInfo 的凭据:

@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    SimpleAuthenticationInfo info = null;
    if (token instanceof UsernamePasswordToken) {
        UsernamePasswordToken uToken = (UsernamePasswordToken) token;
        User user = queryUserByName(uToken.getUsername());
        info = new SimpleAuthenticationInfo(user.getUsername(), user.getPassword().toCharArray(), getName());
        if (user.getSalt() != null) {
            info.setCredentialsSalt(ByteSource.Util.bytes(user.getSalt()));
        }
    } else if (token instanceof OAuthUserToken) {
        OAuthUserToken oToken = (OAuthUserToken) token;
        String type = oToken.getOauthType();
        String openId = oToken.getOpenID();

        //then what should I do to make the `Credentials` check passed?
    }
    return info;
}

如何解决这个问题?

  1. 使用 JWT(Json Web Token)

会话保存到数据库中用于集群部署,但是我们发现它可能会降低我们的响应速度,而且我们需要为移动平台提供api,所以我们尝试使用JWT

虽然似乎 shior 使用 cookie + session 来识别用户是否已通过身份验证。我不知道如何替换它。

有什么建议吗?

【问题讨论】:

    标签: java spring oauth shiro


    【解决方案1】:

    添加新的Realm/Filter/Login url for redirection可能会更好。

    GoogleRealm

    public class GoogleOAuthRealm extends AuthorizingRealm {
        ...
    
        public GoogleOAuthRealm() {
            //OauthToken implements AuthenticationToken to hold code
            setAuthenticationTokenClass(OauthToken.class);
        }
    
        ...
    
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
             OauthToken tk = (OauthToken) token; 
             String authCode = (String) tk.getPrincipal(); 
             //1. fetch token by posting code to google 
             //2. validation & parse token
             //org.apache.shiro.authz.SimpleAuthorizationInfo
             SimpleAuthenticationInfo info = new SimpleAuthenticationInfo();
             //set permission manually
             return info;
        }
        ...
    }
    

    securityManager中配置GoogleRealm,并在google登录成功后重定向到新的url

    public class GoogleAuthenticatingFilter extends FormAuthenticationFilter
    
    <property name="filterChainDefinitions">
        <value> 
            ...
            /login/googleLogin = GoogleAuthenticatingFilter
            ...
        </value>
    </property> 
    

    【讨论】:

      【解决方案2】:

      正如 neuo 上面所写,为 OAuth 使用不同的领域,然后在后端进行一些接线以协调用户凭据。为了您的扩展和性能,我建议使用 Redis 之类的东西作为会话缓存——这样您就不必在数据库中持久化会话。

      【讨论】:

        【解决方案3】:

        重用现有组件

        考虑您正在使用的构造,您可能不想将DatabaseRealm 重用于其他身份验证方案。而是为 Google、Facebook 等创建单独的领域。

        这样你就可以控制AuthenticationTokenAuthenticationInfo在每个领域中的使用。

        JWT/Cookie 会话

        根据您的描述,我认为您可能希望为您的移动平台创建一个 RESTful API。 REST 规范要求服务器不维护,更重要的是不依赖服务器端状态。 幸运的是,shiro 允许您配置在收到请求时不创建会话的端点。更多关于会话管理的细节here

        考虑到上述情况,会话跟踪变得无关紧要,您可以使用 JWT 令牌作为不记名令牌的一种形式,在每个请求上默认验证用户身份。请务必考虑 Bearer 令牌的安全缺陷,这可以通过始终使用加密连接来缓解。

        【讨论】:

          猜你喜欢
          • 2015-01-01
          • 2020-04-30
          • 2012-09-30
          • 1970-01-01
          • 2015-07-18
          • 2015-01-14
          • 1970-01-01
          • 2013-04-24
          • 2019-09-16
          相关资源
          最近更新 更多