我正在使用 NodeJS和Flutter For Web 开发一个全栈应用程序,此刻,我不知道如何进行安全的cookie /令牌会话。 br /> 我需要的答案是如何使用Flutter For Web构建身份验证系统,就像其他社交网络或Stackoverflow本身一样。
答案 0 :(得分:4)
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;
}
}
main.dart:
@override
Widget build(BuildContext context) {
if (kIsWeb) {
isLogin = WebStorage.instance.sessionId != null;
} else {
isLogin = //check from SharedPreferences;
}
return isLogin ? dashboardPage() : loginPage();
}
答案 1 :(得分:4)
这是一个老问题,但所选择的答案并不完全安全。 对于网络而言,将网络存储用于敏感信息并不安全。
您应该使用仅限 http 的 cookie。无法通过 Javascript 读取 Http-only cookie,但浏览器会自动将其发送到后端。
这是 Nodejs-Express-TypeScript 代码示例;
在这个例子中,有两个 cookie,一个是 http-only,另一个不是。 non-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 和特定的端口运行,所以这是我的 Flutter 在 127.0.0.1 上运行的 VsCode 配置
{
"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
}
}