【问题标题】:Shiro authentication with sessionId or username+password使用 sessionId 或用户名+密码的 Shiro 身份验证
【发布时间】:2012-01-20 00:36:44
【问题描述】:

总的来说,我在 Java 身份验证框架和身份验证工作流程方面没有太多经验(只有一些理论知识),因此出于教育目的,我正在尝试为我的 HTTP 应用程序创建这种类型的身份验证:

  1. 客户端将登录名+密码发布到/login
  2. Shiro 通过给定的凭据登录用户。服务器返回客户端他的sessionId
  3. 客户端请求某种资源/myresource?sessionId=1234567
  4. Shiro 通过给定的sessionId 登录主题。然后服务器执行获取/myresource 的常规工作流程(Shiro 管理方法级访问权限)。

基本上我有这些问题:

  1. 我想我不需要 HTTP 会话或 Servlet 会话。 Shiro 有自己的会话管理器,足以满足我的需求。我错了吗?
  2. 向客户端提供真正的 sessionId 是一种好习惯,还是应该发送某种 sessionToken(在服务器端解析为 sessionId)?
  3. 如何使用 sessionId(客户端应存储在本地)登录主题?
  4. 在进行此类身份验证之前,我还需要了解其他任何事情吗?

提前致谢。

【问题讨论】:

    标签: java authentication shiro


    【解决方案1】:

    我想我不需要 HTTP 会话或 Servlet 会话。 Shiro 有自己的会话管理器,足以满足我的需求。我错了吗?

    不,你是对的。这就是Shiro厉害的原因。来自documentation

    Shiro 的 Session 支持比这两种 [web 容器或 EJB Stateful Session Beans] 机制中的任何一种都更易于使用和管理,并且它适用于任何应用程序,无论容器如何。

    例如

    Subject currentUser = SecurityUtils.getSubject();    
    Session session = currentUser.getSession();
    session.setAttribute( "someKey", someValue);
    

    引用the doc:getSession calls work in any application, even non-web applications

    给客户端真正的 sessionId 是一种好习惯,还是应该发送某种 sessionToken(在服务器端解析为 sessionId)?

    发送纯 sessionId 是个坏主意。特别是,如果您通过未加密的网络发送数据。要么使用 HTTPS 之类的东西,要么使用 NONCE 行。

    并且,附带说明,如果通过 http/s POST 数据而不是在 URL 中。

    如何使用 sessionId(客户端应存储在本地)登录主题?

    您的意思是,一旦您拥有会话 ID,您如何验证主题?你可以简单地, 来自文档,

    Subject requestSubject = new Subject.Builder().sessionId(sessionId).buildSubject();
    

    在进行此类身份验证之前,我还需要了解其他任何事情吗?

    是的。

    1. 阅读Shiro's Session Management
    2. 了解MITM Attack
    3. 关于HTTPSSSL
    4. 一些关于哈希函数thisApache Commons DigestUtils,可能是this

    更新

    关于主题身份验证部分 - 它会使新创建的主题成为当前经过身份验证的主题吗?如果不是,我如何使它成为“当前”主题?

    如果您在谈论new Subject.Builder().sessionId(sessionId).buildSubject(),则不会。而且我不知道如何将其设置为线程的 currentUser。 Shiro 的JavaDoc 说,

    [这种方式] 返回的 Subject 实例不会自动绑定到应用程序(线程)以供进一步使用。也就是说,SecurityUtils.getSubject() 不会自动返回与构建器返回的实例相同的实例。如果需要,框架开发人员可以绑定构建的主题以供继续使用。

    所以,如何在当前线程中绑定主题或进一步使用取决于您。

    如果您担心SecurityUtils.getSubject(); thingy 是如何工作的,那么,在 web 容器上下文中,它使用简单的 cookie 来存储您的会话数据。当您的请求通过 Shiro 过滤器时,它会将当前主题附加到其生命周期(当前线程)的请求中。当您作为getSubject() 时,它只是从请求中获取Subject。我发现了一个有趣的线程here

    关于 nonce 部分:如果他向我发送某种哈希而不是他的 sessionId - 我将无法对其进行解码以获得真正的 sessionId(以授权他)。我在这里遗漏了什么吗?

    Nonce 部分 - 脖子疼。现在重新考虑,我认为做 NONCE 只是矫枉过正。让我解释一下,无论如何,

    1. 用户第一次使用他的用户名和密码登录。在客户端设置useridnonce(比如UUID)和HASH(sessionID+nonce),称之为hash1。说,在饼干里。将此nonce 存储在服务器端,可以在数据库或地图中作为user_id <--> nonce,session_id

    2. 在后续请求中,确保您回传useridnonceHASH

    3. 在服务器端,您要做的第一件事是验证请求。根据客户端发送的user_id,获取存储在哈希图或数据库中的sessionIdnonce。创建一个哈希,HASH(sessionId_from_db+nonce_from_db),称之为hash2。

    4. 现在,如果 hash1 与 hash2 匹配,您可以验证请求,并且由于您已将当前 sessionId 存储在服务器端,因此您可以使用它。请求完成后,在 cookie 和服务器端设置新的随机数。

    如果您通过 1 - 4,您会意识到您不需要 Shiro 进行身份验证。 (: 所以,我收回我的话,NONCE 不适用于这种情况,除非您对安全性过于关注性能。

    为什么 MITM 攻击对我很重要?我的客户端(javascript ajax 代码)通过 ajax 从它的服务器获取数据。所以我认为我不应该以任何方式关心 MITM。

    我认为这对你来说应该很重要。 MITM 攻击意味着您的请求/响应正在通过机器 (MITM) 链接到您的路由器。如果它是一个未加密的请求,它对 MITM 来说都是纯文本。他可以看到您的所有请求......并且可能会欺骗请求并可能劫持会话。让我找个例子……http://michael-coates.blogspot.com/2010/03/man-in-middle-attack-explained.html

    【讨论】:

    • 感谢您的详细回答。关于那个主题身份验证部分 - 它会使新创建的Subject 成为当前经过身份验证的主题吗?如果没有,我如何使它成为“当前”主题?
    • 另外,关于 nonce 部分:我需要以某种方式通过它的会话 ID 来识别客户端。如果他向我发送某种哈希而不是他的 sessionId - 我将无法对其进行解码以获取真正的 sessionId(以授权他)。我在这里错过了什么吗?
    • 另外,为什么 MITM 攻击对我很重要?我的客户端(javascript ajax 代码)通过 ajax 从它的服务器获取数据。所以我认为我不应该以任何方式关心 MITM。
    • 再次感谢您的完整回答。
    • 我认为 Subject.Builder().sessionId(sessionId).buildSubject() 仅适用于本机 Shiro 会话(不是容器管理的会话),但我可能错了。
    猜你喜欢
    • 2017-07-31
    • 2011-07-04
    • 2018-07-13
    • 1970-01-01
    • 2014-12-29
    • 2014-03-24
    • 2015-12-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多