【问题标题】:Flutter For Web Cookie/Token Sessions and AuthentcationFlutter 用于 Web Cookie/令牌会话和身份验证
【发布时间】:2019-12-25 20:57:50
【问题描述】:

我正在使用 NodeJS 和 Flutter For Web 开发一个全栈应用程序,目前我不明白如何制作安全的 cookie/令牌会话。 我需要的答案是如何使用 Flutter For Web 制作身份验证系统,就像其他社交网络或 Stackoverflow 本身一样。

【问题讨论】:

  • 可以使用dart:html包手动保存会话信息到cookie。
  • 使用CookieStore
  • @Ryosuke 你能指导我一些 CookieStore 类的使用示例吗?我已经googled 了,但找不到任何有用的东西。
  • 错误 - The class 'CookieStore' doesn't have default constructor.

标签: session cookies flutter dart token


【解决方案1】:

从 Flutter 1.9 直接导入 dart.html 不支持:Reference

我在寻找解决方案时遇到了 universal_html 包,它对我来说工作正常。下面是我在网络上本地存储键值对的辅助类:

import 'package:universal_html/prefer_universal/html.dart';

class WebStorage {

  //Singleton
  WebStorage._internal();
  static final WebStorage instance = WebStorage._internal();
  factory WebStorage() {
    return instance;
  }

  String get sessionId => window.localStorage['SessionId'];
  set sessionId(String sid) => (sid == null) ? window.localStorage.remove('SessionId') : window.localStorage['SessionId'] = sid;
}

阅读,

WebStorage.instance.sessionId;

写作,

WebStorage.instance.sessionId = 'YOUR_CREDENTIAL';

示例:

fetchPost(params, "CMD_USERREGISTRATION").then((result) {
        ...
        APIResponse response = APIResponse(xmlString: result.body);

        if (!response.isSuccess()) {
          ...
          return;
        }
        var sid = response.getSessionId();

        if (kIsWeb) {
          WebStorage.instance.sessionId = sid;
        }
}

ma​​in.dart:

@override
  Widget build(BuildContext context) {
    if (kIsWeb) {
      isLogin = WebStorage.instance.sessionId != null;
    } else {
      isLogin = //check from SharedPreferences;
    }
    return isLogin ? dashboardPage() : loginPage();
  }

更新:

shared_preferences 现在从 0.5.6 版本开始支持 Web。另见shared_preferences_web

【讨论】:

  • 好的,但是现在我有一个 sessionId 我该如何使用它?你能用get或post之类的路由展示这个类的例子吗?
  • @Stecco 我已经编辑了我的答案以包含示例。请看一下。
  • Flutter_Secure_StorageCookie[Secure/HTTPOnly] 都为 SECURITY 提供选项,第一个为 Android(和其他原生平台)提供加密存储,第二个防止 @987654331 @ 要知道明智的 cookie,请自行承担风险!但另一方面,您可以使用 bool(True/Fale) 等简单类型设置登录状态并处理后端响应以检查 SessionID/Credential 是否有效...
  • 还有shared_preferences 泄漏与WebStorage 相同,用于明智的cookie...
【解决方案2】:

这是一个老问题,但选择的答案并不完全安全。 对于网络而言,使用网络存储来存储敏感信息并不安全。

您应该使用仅限 http 的 cookie。仅 Http cookie 无法通过 Javascript 读取,但浏览器会自动将其发送到后端。

这里是 Nodejs-Express-TypeScript 代码示例;

在这个例子中,有两个 cookie 一个是 http-only,另一个不是。 非 http-only cookie 用于检查登录情况,如果它是有效的客户端假定用户已登录。但实际控制由后端完成。

PS:不需要存储或发送任何令牌,因为浏览器会自动处理它(cookies)。

const cookieConfig = {
  httpOnly: true,
  secure,
  maxAge: 30 * 24 * 60 * 60 * 1000,
  signed: secure,
}

const cookieConfigReadable = {
  httpOnly: false,
  secure,
  maxAge: 30 * 24 * 60 * 60 * 1000,
  signed: secure,
}

function signToken(unsignedToken: any) {
  const token = jwt.sign(unsignedToken, privatekey, {
    algorithm: 'HS256',
    expiresIn: jwtExpirySeconds,
  })

  return token
}

const tokenObj = {
  UID: userId,
  SID: sessionId,
}

const token = signToken(tokenObj)

// sets session info to the http-only cookie
res.cookie('HSINF', token, cookieConfig) 

// sets a cookie with expires=false value for client side check.
res.cookie('expired', false, cookieConfigReadable) 

但是这种方法在调试过程中存在挑战,因为 NodeJS 和 Flutter Web 服务于不同的端口,你应该允许 CORS 用于开发环境。

if (process.env.NODE_ENV === 'dev') {
  app.use(
    cors({
      origin: [
        'http://localhost:8080',
        'http://127.0.0.1:8080',
      ],
      credentials: true,
    }),
  )
}

而且在 Flutter Web 中,你不能在调试时直接使用 http.get 或 http.post,因为 Flutter 默认禁用 CORS cookie。

这是一个解决方法。

// withCredentials = true is the magic
var client = BrowserClient()..withCredentials = true;
http.Response response;
try {
  response = await client.get(
    Uri.parse(url),
    headers: allHeaders,
  );
} finally {
  client.close();
}

在调试方面还有另一个挑战;许多浏览器不允许 localhost 使用 cookie,您应该使用 127.0.0.1 代替。但是 Flutter Web 只针对特定的 url 和特定的端口运行,所以这是我的 VsCode 配置,让 Flutter 在 127.0.0.1 上运行

 {
      "name": "project",
      "request": "launch",
      "type": "dart",
      "program": "lib/main.dart",
      "args": [
        "-d",
        "chrome",
        "--web-port",
        "8080",
        "--web-hostname",
        "127.0.0.1"
      ]
    }

这些用于设置和传输 cookie,您可以在下面找到我的后端 cookie 检查

const httpOnlyCookie = req.signedCookies.HSINF
const normalCookie = req.signedCookies.expired

if (httpOnlyCookie && normalCookie === 'false') {
  token = httpOnlyCookie
}

if (token) {
  let decoded: any = null
  try {
    decoded = jwt.verify(token, privatekey)
  } catch (ex) {
    Logger.error(null, ex.message)
  }

  if (decoded) {
    //Cookie is valid, get user with the session id
  }
}

【讨论】:

  • 我正在尝试您的工作,但 Chrome 不会在 FlutterWeb 中保留 HttpOnly cookie!似乎只是丢掉它们!?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-09-29
  • 2019-03-05
  • 2016-02-22
  • 2018-01-08
  • 2010-09-26
  • 1970-01-01
  • 2015-03-25
相关资源
最近更新 更多