如何在 Flutter 和 Nestjs 中使用 Session?
How to use Sessions with Flutter and Nestjs?
我试图让用户使用 nestjs 后端登录,当我使用 Postman 时,这个过程非常顺利,但是对于 Flutter,我不知道该怎么做。我不认为我真的了解会话如何在手机上工作,我试图寻找一些适当的解释,但到目前为止我找不到任何东西。
Nestjs 代码
@Controller('users')
@Serialize(UserDto)
export class UsersController {
constructor(
private usersService: UsersService,
private authService: AuthService,
) {}
@Get('/whoami')
@UseGuards(AuthGuard)
whoAmI(@currentUser() user: User) {
return user;
}
@Get()
getUsers(@Query('email') email: string) {
return this.usersService.find(email);
}
@Post('/signup')
async sendUser(@Body() body: UserDto, @Session() session: any) {
console.log(body);
const user = await this.authService.signup(body.email, body.password);
session.userId = user.id;
console.log(session.userId);
return user;
}
@Post('/signin')
async signin(@Body() body: UserDto, @Session() session: any) {
const user = await this.authService.signin(body.email, body.password);
session.userId = user.id;
console.log(session.userId);
return user;
}
@Post('/signout')
async signout(@Session() session: any) {
console.log(session.userId);
if (!session.userId) {
throw new NotFoundException('user not found');
}
session.userId = null;
}
}
Flutter 代码
Future<void> signin(
String username, String password, BuildContext context) async {
try {
var url = 'https://example-app.herokuapp.com/users/signin';
var dio = Dio();
var response =
await dio.post(url, data: {'email': username, 'password': password}, options: Options(headers: {'Accept': 'application/json'}));
print(response.headers);
// response;
Navigator.of(context).pushNamed(CategoryDetailScreen.routeName);
} catch (err) {
print(err);
throw err;
}
}
Future<void> signout() async {
try {
var url = 'https://example-app.herokuapp.com/users/signout';
var dio = Dio();
var response = await dio.post(url,
options: Options(headers: {
'cookie':
'key'
}
)
);
print(response.headers);
response;
// return response;
} catch (err) {
print(err);
throw err;
}
}
感谢@RichardHeap 的评论,我设法解决了我的问题。
Check out session management with cookies:
我使用 FlutterSecureStorage
包来存储传入的 cookie,然后使用 FutureBuilder
决定将哪个屏幕显示为主屏幕,如下所示:
我使用这些函数来写入 cookie 并将它们从设备中删除:
Future<void> signin(
String username, String password, BuildContext context) async {
try {
// String cookie = '';
var url = 'https://daleel-app.herokuapp.com/users/signin';
var storage = FlutterSecureStorage();
var dio = Dio();
var response =
await dio.post(url, data: {'email': username, 'password': password});
List<String>? cookies = response.headers['set-cookie'];
for (int i = 0; i <= cookies!.length - 1; i++) {
var cokIndex = cookies[i].indexOf(';');
var subCookies = cookies[i].substring(0, cokIndex + 1);
cookie += subCookies + ' ';
}
var subbedCookie = cookie.substring(0, cookie.length - 2);
print(subbedCookie);
storage.write(key: 'cookie', value: subbedCookie);
loggedIn = true;
// print(response.headers['set-cookie']);
// [express:sess=eyJ1c2VySWQiOjU1fQ==; path=/; httponly, express:sess.sig=Zy_Lc7kXM1BqZKIZRRt7ygpCTrM; path=/; httponly]
Navigator.of(context).pushNamed(CategoryDetailScreen.routeName);
} catch (err) {
print(err);
throw err;
}
}
Future<void> signout(BuildContext context) async {
try {
var url = 'https://daleel-app.herokuapp.com/users/signout';
var dio = Dio();
var fStorage = FlutterSecureStorage();
var header = await fStorage.read(key: 'cookie');
await dio.post(url, options: Options(headers: {'cookie': header}));
fStorage.delete(key: 'cookie');
Navigator.of(context).pushReplacementNamed(LoginScreen.routeName);
print('you reached here');
} catch (err) {
print(err);
throw err;
}
}
这里我使用 FutureBuilder 来决定显示哪个屏幕:
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
var cookie = FlutterSecureStorage().read(key: 'cookie');
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(
create: (ctx) => Places(),
),
ChangeNotifierProvider(
create: (ctx) => Offers(),
),
],
child: FutureBuilder(
future: cookie,
builder: (BuildContext context, AsyncSnapshot snapshot) => MaterialApp(
debugShowCheckedModeBanner: true,
title: 'Daleel',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: snapshot.hasData ? HomeScreen() : LoginScreen(),
routes: {
LoginScreen.routeName: (ctx) => LoginScreen(),
TestScreen3.routeName: (ctx) => TestScreen3(),
TestScreen2.routeName: (ctx) => TestScreen2(),
HomeScreen.routeName: (ctx) => HomeScreen(),
DetailsScreen.routeName: (ctx) => DetailsScreen(),
ExploreScreen.routeName: (ctx) => ExploreScreen(),
CategoryDetailScreen.routeName: (ctx) => CategoryDetailScreen(),
SearchDetailsScreen.routeName: (ctx) => SearchDetailsScreen(),
}),
),
);
}
}
我试图让用户使用 nestjs 后端登录,当我使用 Postman 时,这个过程非常顺利,但是对于 Flutter,我不知道该怎么做。我不认为我真的了解会话如何在手机上工作,我试图寻找一些适当的解释,但到目前为止我找不到任何东西。
Nestjs 代码
@Controller('users')
@Serialize(UserDto)
export class UsersController {
constructor(
private usersService: UsersService,
private authService: AuthService,
) {}
@Get('/whoami')
@UseGuards(AuthGuard)
whoAmI(@currentUser() user: User) {
return user;
}
@Get()
getUsers(@Query('email') email: string) {
return this.usersService.find(email);
}
@Post('/signup')
async sendUser(@Body() body: UserDto, @Session() session: any) {
console.log(body);
const user = await this.authService.signup(body.email, body.password);
session.userId = user.id;
console.log(session.userId);
return user;
}
@Post('/signin')
async signin(@Body() body: UserDto, @Session() session: any) {
const user = await this.authService.signin(body.email, body.password);
session.userId = user.id;
console.log(session.userId);
return user;
}
@Post('/signout')
async signout(@Session() session: any) {
console.log(session.userId);
if (!session.userId) {
throw new NotFoundException('user not found');
}
session.userId = null;
}
}
Flutter 代码
Future<void> signin(
String username, String password, BuildContext context) async {
try {
var url = 'https://example-app.herokuapp.com/users/signin';
var dio = Dio();
var response =
await dio.post(url, data: {'email': username, 'password': password}, options: Options(headers: {'Accept': 'application/json'}));
print(response.headers);
// response;
Navigator.of(context).pushNamed(CategoryDetailScreen.routeName);
} catch (err) {
print(err);
throw err;
}
}
Future<void> signout() async {
try {
var url = 'https://example-app.herokuapp.com/users/signout';
var dio = Dio();
var response = await dio.post(url,
options: Options(headers: {
'cookie':
'key'
}
)
);
print(response.headers);
response;
// return response;
} catch (err) {
print(err);
throw err;
}
}
感谢@RichardHeap 的评论,我设法解决了我的问题。
Check out session management with cookies:
我使用 FlutterSecureStorage
包来存储传入的 cookie,然后使用 FutureBuilder
决定将哪个屏幕显示为主屏幕,如下所示:
我使用这些函数来写入 cookie 并将它们从设备中删除:
Future<void> signin(
String username, String password, BuildContext context) async {
try {
// String cookie = '';
var url = 'https://daleel-app.herokuapp.com/users/signin';
var storage = FlutterSecureStorage();
var dio = Dio();
var response =
await dio.post(url, data: {'email': username, 'password': password});
List<String>? cookies = response.headers['set-cookie'];
for (int i = 0; i <= cookies!.length - 1; i++) {
var cokIndex = cookies[i].indexOf(';');
var subCookies = cookies[i].substring(0, cokIndex + 1);
cookie += subCookies + ' ';
}
var subbedCookie = cookie.substring(0, cookie.length - 2);
print(subbedCookie);
storage.write(key: 'cookie', value: subbedCookie);
loggedIn = true;
// print(response.headers['set-cookie']);
// [express:sess=eyJ1c2VySWQiOjU1fQ==; path=/; httponly, express:sess.sig=Zy_Lc7kXM1BqZKIZRRt7ygpCTrM; path=/; httponly]
Navigator.of(context).pushNamed(CategoryDetailScreen.routeName);
} catch (err) {
print(err);
throw err;
}
}
Future<void> signout(BuildContext context) async {
try {
var url = 'https://daleel-app.herokuapp.com/users/signout';
var dio = Dio();
var fStorage = FlutterSecureStorage();
var header = await fStorage.read(key: 'cookie');
await dio.post(url, options: Options(headers: {'cookie': header}));
fStorage.delete(key: 'cookie');
Navigator.of(context).pushReplacementNamed(LoginScreen.routeName);
print('you reached here');
} catch (err) {
print(err);
throw err;
}
}
这里我使用 FutureBuilder 来决定显示哪个屏幕:
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
var cookie = FlutterSecureStorage().read(key: 'cookie');
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(
create: (ctx) => Places(),
),
ChangeNotifierProvider(
create: (ctx) => Offers(),
),
],
child: FutureBuilder(
future: cookie,
builder: (BuildContext context, AsyncSnapshot snapshot) => MaterialApp(
debugShowCheckedModeBanner: true,
title: 'Daleel',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: snapshot.hasData ? HomeScreen() : LoginScreen(),
routes: {
LoginScreen.routeName: (ctx) => LoginScreen(),
TestScreen3.routeName: (ctx) => TestScreen3(),
TestScreen2.routeName: (ctx) => TestScreen2(),
HomeScreen.routeName: (ctx) => HomeScreen(),
DetailsScreen.routeName: (ctx) => DetailsScreen(),
ExploreScreen.routeName: (ctx) => ExploreScreen(),
CategoryDetailScreen.routeName: (ctx) => CategoryDetailScreen(),
SearchDetailsScreen.routeName: (ctx) => SearchDetailsScreen(),
}),
),
);
}
}