如何模拟RESTful服务(Grails,Shiro)的会话cookie?

3

我有一个现有的Grails应用程序,其中使用Nimble插件(因此在其下面使用Apache Shiro安全)。

我正在为它添加RESTful JSON API。

我的login方法成功获取来自Shiro的会话ID,并将其返回给客户端:

class ApiController {
    def login(String username, String password) {
        def authToken = new UsernamePasswordToken(username, password)
        SecurityUtils.subject.login(authToken)

        render(contentType:"text/json") {
            [
                sessionId: SecurityUtils.subject.getSession().getId()
            ]
        }
    }

    def getData() {
        SecurityUtils.subject... // either expect to already find a properly populated SecurityUtils.subject or a way to otherwise get it
    }
}

这看起来像是:
{"sessionId":"61FE89F60F94A4EF7B796783E7A326BC"}

这很令人鼓舞,因为它与我在浏览器中看到的cookie传递时使用的相同。

Cookie:auth=Z3Vlc3Q6dGx1c2lz; m=2663:t|34e2:|47ba:t|4e99:t|6ef2:t|370d:t|3c0d:t|64b8:t|2a03:t|18c3:t|79d4:chart|640c:small|678e:3600%7C60|796a:t; OX_plg=swf|sl|wmp|shk|pm; _ga=GA1.1.441292120.1405856016; __atuvc=0%7C47%2C0%7C48%2C0%7C49%2C432%7C50%2C17%7C51; JSESSIONID=61FE89F60F94A4EF7B796783E7A326BC

然而,我现在无法弄清楚如何正确地传递这个JSESSIONID,以便现有的Nimble/Shiro/Grails/Servlet(不确定是哪个级别)身份验证过滤器将其识别为正确的会话标识符,并将请求与会话关联。我尝试手动传递一个Cookie,格式为JSESSIONID=<sessionId>(在Android上使用Dispatch),但它似乎没有效果(虽然也许我对newValidCookie的参数并不全都正确)。
val cookie = com.ning.http.client.cookie.Cookie.newValidCookie("JSESSIONID", token, null, token, null, -1, -1, false, false)
val svc = host / "api" / "getData" addCookie cookie
Http(svc OK as.String) 

我还尝试在URL后添加;jsessionid=<sessionId>,但这也没有任何效果。
我还尝试在getData()中执行new Subject.Builder().sessionId(sessionId).buildSubject();,但那里的.sessionId()不接受String
到目前为止,我还没有确定会话cookie的处理发生在哪里。
我该如何正确组装会话cookie,以便移动应用程序可以像Web客户端一样使用应用程序?
附言:我的计划B是在每个请求的身份验证标头中传递用户名/密码,并让ApiController每次都执行subject.login,但我更喜欢使用已用于Web应用程序的会话ID来完成它。

你解决了什么问题吗?我也遇到了同样的问题。 - Shweta Gulati
1个回答

0

似乎有一些称为自定义主题实例(https://shiro.apache.org/subject.html#custom-subject-instances)的东西

有两个步骤:

  1. 创建主题(使用构建器)
  2. 将主题与线程关联(有多种方法可以实现此操作)

未经测试的示例:

Serializable sessionId = //acquired from somewhere 
Subject subject = new Subject.Builder().sessionId(sessionId).buildSubject();

ThreadState threadState = new SubjectThreadState(subject);
threadState.bind();
try {
    //execute work as the built Subject
} finally {
    //ensure any state is cleaned so the thread won't be
    //corrupt in a reusable or pooled thread environment
    threadState.clear();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接