使用 Android 登录时未设置 Passport.js 会话
Posted
技术标签:
【中文标题】使用 Android 登录时未设置 Passport.js 会话【英文标题】:Passport.js sessions are not set when Login with Android 【发布时间】:2016-12-04 03:33:51 【问题描述】:在我的 AuthController.js 中,我检查登录是否成功并在会话中设置哈希码:
req.logIn(user, function (err)
if (err) res.send(err);
var redirectTo = req.session.redirectTo ? req.session.redirectTo : '/user/show/'+user.id;
delete req.session.redirectTo;
bcrypt.genSalt(10, function (err, salt)
bcrypt.hash(user.email, salt, function (err, hash)
if (err)
console.log(err);
else
req.session.passport.user_type = user.type;
req.session.passport.user_avatar = user.avatar;
req.session.passport.email = user.email;
req.session.passport.token = hash;
// here session is set! also when login with android
console.log("User passport Sessions: ",req.session.passport)
res.json(user);
res.end();
);
)
)
当我使用浏览器登录时设置会话 - 我使用另一个简单的控制器检查它们:
'who': function (req, res)
res.json(req.session);
,
当我使用我的 Android 应用程序(Volley 请求)登录时,一切都按预期工作,但是当我在成功登录后向这个“谁”控制器发出新请求时,整个“护照”属性为空。
为什么我使用 Android App 登录时没有设置护照会话?
问题是:凌空请求与浏览器请求不同吗?当服务器无法为 volley 请求保存会话时,我如何在服务器上知道(在第二个请求中)用户已经登录?
我转储了 req.headers,这就是 Chrome 的样子:
host: 'localhost:1337',
connection: 'keep-alive',
'cache-control': 'max-age=0',
'upgrade-insecure-requests': '1',
'user-agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/51.0.2704.103 Safari/537.36',
accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'accept-encoding': 'gzip, deflate, sdch',
'accept-language': 'de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4',
cookie: '__utma=111872281.1508283337.1455636609.1455636609.1455636609.1; __utmz=111872281.1455636609.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); _ga=GA1.1.1508283337.1455636609; sails.sid=s%3AHNW3D3ktwA79IFHH4gX9Ko6o73MZOjRK.I7sTYkCKSkkwset6OC2ap58fcROPtV6PqUnkaInGW44',
'if-none-match': 'W/"1f3e-WoreHgYUy3uvXGNH++ttsQ"'
这就是 Android 请求通过 Volley 的样子:
'user-agent': 'Dalvik/2.1.0 (Linux; U; Android 6.0; Android SDK built for x86 Build/MASTER)',
host: '10.0.2.2:1337',
connection: 'Keep-Alive',
'accept-encoding': 'gzip'
'if-none-match': 'W/"1f3e-WoreHgYUy3uvXGNH++ttsQ"',
'user-agent': 'Dalvik/2.1.0 (Linux; U; Android 6.0; Android SDK built for x86 Build/MASTER)',
host: '10.0.2.2:1337',
connection: 'Keep-Alive',
'accept-encoding': 'gzip'
缺少会话部分 - 同时我知道您必须自己实现会话管理。是否有针对 Volley 上的多个 HTTP 请求的简单教程?
【问题讨论】:
【参考方案1】:好吧 10 天后我知道如何“解决”这个问题。
当你向你的服务器发出请求时,你会得到一堆东西。标题对我们来说很重要。
在此处阅读有关 HTTP 标头的更多信息: http://code.tutsplus.com/tutorials/http-headers-for-dummies--net-8039
HTTP 请求是无状态的,也就是说,它不保存有关客户端的信息和状态。
Volley 不处理头球。我们要做的是:
当我们从 App 发出第一个请求时,我们必须保存响应头信息。
"Access-Control-Allow-Credentials":"","Access-Control-Allow-Headers":"","Access-Control-Allow-Methods":"","Access-Control-Allow-Origin":"","Access-Control-Expose-Headers":"","Connection":"keep-alive","Content-Length":"235","Content-Type":"application\/json; charset=utf-8","Date":"Tue, 09 Aug 2016 22:39:40 GMT","ETag":"W\/\"eb-bxZXjFIir0ihzYNPgoUbTg\"","set-cookie":"sails.sid=s%3AsjQL1FsAJY5VWGHdgChpa0hgZPs06AH9z.H1RLNh%2FMqLjxdGtKtnWFv8cFO8WjeAUhPFQp2Yl73Lo; Path=\/; HttpOnly","Vary":"X-HTTP-Method-Override","X-Android-Received-Millis":"1470713694296","X-Android-Response-Source":"NETWORK 200","X-Android-Selected-Protocol":"http\/1.1","X-Android-Sent-Millis":"1470713694119","X-Powered-By":"Sails <sailsjs.org>"
标题中的重要信息是“set-cookie”部分。我们必须从第一次调用中保存这些信息,并在下一个请求中重复使用它,以便服务器知道我们是谁。
怎么做?
我使用了来自 djodjo 的自定义请求。重要的方法是 parseNetworkResponse: https://***.com/a/36435582/3037960
我们像这样使用这个类:
mHeaders = new HashMap<String, String>();
session = new SessionManager(myView.getContext());
registerRequest = new MetaRequest(1, MY_ENDPOINT, obj, new Response.Listener<JSONObject>()
@Override
public void onResponse(JSONObject response)
JSONObject headers = new JSONObject();
try
headers.put("headers", response.get("headers"));
// get the "set-cookie" value
String sailsSession = String.valueOf(headers.getJSONObject("headers").get("set-cookie"));
Log.d("Response Headers", sailsSession);
// Session Manager
session.storeSailsSession(sailsSession);
String cookie = session.getSailsSession();
if( cookie != null)
//just to test if the cookie is now saved?
Log.d("Cookies", cookie);
catch (JSONException e)
e.printStackTrace();
, new Response.ErrorListener()
@Override
public void onErrorResponse(VolleyError error)
Log.d("ERROR", String.valueOf(error));
// TODO Auto-generated method stub
)
public Map<String, String> getHeaders()
return mHeaders;
;
RequestQueue queue = Volley.newRequestQueue(getActivity());
queue.add(registerRequest);
你看到那里有会话管理器... session.storeSailsSession(sailsSession); 这是一个自定义类,用于将我们的 cookie 保存在共享首选项中,以便我们可以获取此信息当我们需要它们时,在应用程序中整体显示。
public class SessionManager
// Shared Preferences
SharedPreferences pref;
// Editor for Shared preferences
Editor editor;
// Context
Context _context;
// User hash/cookie
public static final String KEY_SESSION = "session";
// Constructor
public SessionManager(Context context)
this._context = context;
pref = _context.getSharedPreferences(PREF_NAME, 0);
editor = pref.edit();
public void storeSailsSession(String session)
editor.putString(KEY_SESSION,session);
editor.commit();
public String getSailsSession()
return pref.getString(KEY_SESSION,null);
您现在了解如何从标头中获取 cookie,如何存储它们以备后用;现在对于下一个请求如何设置标头?
在发送请求之前(您不必使用上面的自定义 MetaRequest),您必须从共享首选项中获取会话,然后在哈希映射 mHeaders 中设置它:
String sailsCookie = session.getSailsSession();
mHeaders.put("cookie", sailsCookie.toString());
并且不要忘记将 mHeaders 返回到您的请求中,如下所示:
JsonArrayRequest arrayreq = new JsonArrayRequest(JsonURL,Listener,ErrorListener)
public Map<String, String> getHeaders()
return mHeaders;
通常你只使用 new WhatEverRequest(....); 但现在你必须附加 ... return mHeaders;
希望你能理解,否则就发表评论,我会解释的。对我来说它有效,所以我相信它也适用于你。下次推荐你使用https://jwt.io
【讨论】:
我又来了,1.5 个月后:使用改造!改造就像 1000 倍容易和更好 - 我希望我知道它futurestud.io/tutorials/retrofit-add-custom-request-header以上是关于使用 Android 登录时未设置 Passport.js 会话的主要内容,如果未能解决你的问题,请参考以下文章
直接访问登录表单时未设置会话 cookie,导致 CSRF 令牌无效
swift - xcode 11中使用frame = bound选项时未对齐