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

时间:2014-12-16 19:37:31

标签: session grails cookies session-cookies shiro

我有一个使用Nimble插件的Grails应用程序(因此下面是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(不确定哪个级别)身份验证过滤器将其识别为正确的会话标识符并将请求与会话相关联。

我尝试使用JSESSIONID=<sessionId>手动传递Cookie(在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) 

我还尝试将;jsessionid=<sessionId>附加到网址上,但也没有做任何事情。

我也尝试在new Subject.Builder().sessionId(sessionId).buildSubject();中执行getData(),但.sessionId()并不像String

到目前为止,我还没有弄清楚会话cookie处理的确切位置。

如何正确组装会话cookie,以便移动应用程序可以像使用Web客户端一样使用该应用程序?

P.S。我的计划B是在每次请求时简单地在身份验证标头中传递用户名/密码,并且ApiController每次都subject.login执行{{1}},但我更愿意使用会话ID来执行此操作#39;已经用于Web应用程序。

1 个答案:

答案 0 :(得分:0)

似乎有一种叫做自定义主题实例(https://shiro.apache.org/subject.html#custom-subject-instances

的东西

有两个步骤:

  1. 创建主题(使用构建器)
  2. 将主题与主题相关联(许多方法)
  3. 未经测试的例子:

    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();
    }