Flutter会话管理插件shelf_session的使用

发布于 1周前 作者 htzhanglong 来自 Flutter

Flutter会话管理插件shelf_session的使用

shelf_session 是一个用于 shelf 的中间件实现,包括 cookiesMiddlewaresessionMiddleware

关于

shelf_session 提供了两个中间件:

  • cookiesMiddleware
  • sessionMiddleware

cookiesMiddleware 可以独立使用。sessionMiddleware 依赖于 cookiesMiddleware 并且必须在其之后使用。

final pipeline = const Pipeline()
    .addMiddleware(cookiesMiddleware())
    .addMiddleware(sessionMiddleware())
    .addHandler(handler);

示例代码

以下是一个简单的可运行示例:

import 'dart:io' show Cookie;

import 'package:shelf/shelf.dart';
import 'package:shelf/shelf_io.dart' as io;
import 'package:shelf_router/shelf_router.dart';
import 'package:shelf_session/cookies_middleware.dart';
import 'package:shelf_session/session_middleware.dart';
import 'package:shelf_static/shelf_static.dart';

void main(List<String> args) async {
  final router = Router();
  router.get('/', _handleHome);
  router.get('/login', _handleLogin);
  router.get('/login/', _handleLogin);
  router.post('/login', _handleLogin);
  router.post('/login/', _handleLogin);
  router.get('/logout', _handleLogout);
  router.get('/logout/', _handleLogout);
  final staticHandler = createStaticHandler('web', defaultDocument: 'index.html');
  final handler = Cascade().add(staticHandler).add(router).handler;
  final pipeline = const Pipeline()
      .addMiddleware(logRequests())
      .addMiddleware(cookiesMiddleware())
      .addMiddleware(sessionMiddleware())
      .addHandler(handler);
  const address = 'localhost';
  const port = 8080;
  final server = await io.serve(pipeline, address, port);
  print('Serving at http://${server.address.host}:${server.port}');
}

const _menu = '''
<a href="/">Home</a><br />
<a href="/login">Log in</a><br />
<a href="/logout">Log out</a><br />''';

Future<Response> _handleHome(Request request) async {
  final userManager = UserManager();
  final user = userManager.getUser(request);
  var body = '$_menu{{message}}<br />{{cookies}}';
  if (user == null) {
    body = body.replaceAll('{{message}}', 'You are not logged in');
  } else {
    body = body.replaceAll('{{message}}', 'You are logged in as ${user.name}');
  }

  final cookies = request.getCookies();
  body = body.replaceAll('{{cookies}}',
      cookies.entries.map((e) => '${e.key}: ${e.value}').join('<br />'));
  request.addCookie(Cookie('foo', 'Foo'));
  if (!cookies.containsKey('baz')) {
    request.addCookie(Cookie('baz', 'Baz'));
  } else {
    request.removeCookie(Cookie('baz', ''));
  }

  return _render(body);
}

Future<Response> _handleLogin(Request request) async {
  const html = '''
<form action="" method="post">
<label>Login</label><br />
<input name="login" type="text" /><br />
<label>Password</label><br />
<input name="password" type="password" /><br /><br />
<button>Log in</button>
</form>
''';

  if (request.method == 'GET') {
    return _render(_menu + html);
  }

  final body = await request.readAsString();
  final queryParameters = Uri(query: body).queryParameters;
  final login = queryParameters['login'] ?? ''
    ..trim();
  final password = queryParameters['password'] ?? ''
    ..trim();
  if (login.isEmpty || password.isEmpty) {
    return _render(_menu + html);
  }

  final user = User(login);
  final userManager = UserManager();
  userManager.setUser(request, user);
  return Response.found('/');
}

Future<Response> _handleLogout(Request request) async {
  Session.deleteSession(request);
  return Response.found('/');
}

Response _render(String body) {
  return Response.ok(body, headers: {
    'Content-type': 'text/html; charset=UTF-8',
  });
}

class User {
  final String name;

  User(this.name);
}

class UserManager {
  User? getUser(Request request) {
    final session = Session.getSession(request);
    if (session == null) {
      return null;
    }

    final user = session.data['user'];
    if (user is User) {
      return user;
    }

    return null;
  }

  User setUser(Request request, User user) {
    var session = Session.getSession(request);
    session ??= Session.createSession(request);
    session.data['user'] = user;
    return user;
  }
}

更多关于Flutter会话管理插件shelf_session的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter会话管理插件shelf_session的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中使用shelf_session插件进行会话管理的示例代码。shelf_session是一个基于Dart的Shelf服务器的会话管理中间件,虽然它不是直接用于Flutter客户端,但你可以结合Flutter的HTTP请求和Shelf服务器来实现会话管理。

首先,你需要确保你的Dart环境已经设置好,并且已经创建了一个Flutter项目。接着,你可以在项目的pubspec.yaml文件中添加shelfshelf_session的依赖,但请注意,这些依赖通常用于服务器端代码,而不是Flutter客户端代码。Flutter客户端将通过HTTP请求与Shelf服务器交互。

服务器端代码(使用shelf和shelf_session)

  1. 创建shelf服务器并设置会话管理
// pubspec.yaml
dependencies:
  shelf: ^1.2.0
  shelf_router: ^1.0.0
  shelf_session: ^0.2.0
  crypto: ^3.0.1 # 用于会话加密

// server.dart
import 'dart:convert';
import 'dart:io';
import 'package:shelf/shelf.dart';
import 'package:shelf_router/shelf_router.dart';
import 'package:shelf_session/shelf_session.dart';
import 'package:crypto/crypto.dart';

void main() {
  var parser = new MultipartFormDataParser();
  var sessionMiddleware = createSessionMiddleware({
    'secret': 'your-secret-key', // 用于加密会话ID的密钥
    'cookieName': 'sessionId',
    'duration': const Duration(days: 7), // 会话有效期
  });

  var handler = Router()
    ..post('/login', _handleLogin)
    ..get('/protected', _handleProtected);

  var app = Pipeline().addMiddleware(sessionMiddleware).addHandler(handler);

  var server = await HttpServer.bind(InternetAddress.ANY_IP_V4, 8080);
  print('Serving at http://${server.address.host}:${server.port}');
  await for (var request in server) {
    var response = await app.call(request);
    await response.close();
  }
}

Future<Response> _handleLogin(Request request) async {
  var form = await request.parseFormData();
  var username = form['username']?.first;
  var password = form['password']?.first;

  // 这里应该进行实际的用户验证,这里只是示例
  if (username == 'admin' && password == 'password') {
    var session = request.context['session'] as Map<String, dynamic>;
    session['userId'] = '123'; // 假设用户ID为123
    return Response.ok('Login successful');
  } else {
    return Response.unauthorized('Invalid credentials');
  }
}

Future<Response> _handleProtected(Request request) async {
  var session = request.context['session'] as Map<String, dynamic>;
  if (session?.containsKey('userId') ?? false) {
    return Response.ok('Welcome, protected content!');
  } else {
    return Response.unauthorized('Unauthorized');
  }
}

Flutter客户端代码

  1. 在Flutter客户端中发送HTTP请求
// pubspec.yaml
dependencies:
  flutter:
    sdk: flutter
  http: ^0.13.3 # 用于发送HTTP请求

// main.dart
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter Shelf Session Example'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              ElevatedButton(
                onPressed: () async {
                  await login(context, 'admin', 'password');
                },
                child: Text('Login'),
              ),
              SizedBox(height: 20),
              ElevatedButton(
                onPressed: () async {
                  await fetchProtectedContent(context);
                },
                child: Text('Fetch Protected Content'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Future<void> login(BuildContext context, String username, String password) async {
  var url = Uri.parse('http://localhost:8080/login');
  var response = await http.post(
    url,
    body: {
      'username': username,
      'password': password,
    },
  );

  if (response.statusCode == 200) {
    ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Login successful')));
  } else {
    ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Login failed')));
  }
}

Future<void> fetchProtectedContent(BuildContext context) async {
  var url = Uri.parse('http://localhost:8080/protected');
  var response = await http.get(url);

  if (response.statusCode == 200) {
    ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(response.body)));
  } else {
    ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Unauthorized')));
  }
}

说明

  • 服务器端:我们创建了一个简单的Shelf服务器,它使用shelf_session进行会话管理。/login端点用于用户登录,并在验证成功后设置会话。/protected端点检查会话是否存在,如果存在则返回受保护的内容。
  • 客户端:Flutter客户端使用http包发送HTTP请求到服务器。登录成功后,用户可以请求受保护的内容。

请注意,这只是一个基本示例,实际应用中你可能需要处理更多的边缘情况和安全性问题,比如HTTPS、CSRF保护、更复杂的用户验证逻辑等。

回到顶部