OpenHarmony开发者论坛
标题:
如何在Http请求中使用Cookie传递用户token,实现登录状态保持。
[打印本页]
作者:
深开鸿-孙炼
时间:
2024-6-14 15:55
标题:
如何在Http请求中使用Cookie传递用户token,实现登录状态保持。
[md]# 前言
OpenHarmony作为万物互联的操作系统,网络连接是最基础的能力。其中,有大量的网络应用需要进行用户认证,那么在OpenHarmony的应用开发中,用户登录后,如何在Http请求中使用Cookie传递用户token,实现登录状态保持?
# 需求
在OpenHarmony中使用[*@ohos.net.http*](
https://docs.openharmony.cn/page ... pis/js-apis-http.md
"@ohos.net.http")模块实现网络请求,我们需要实现网络应用用户登录及登录状态保持,但在接口介绍文档、Sample中并未提供如何保存及使用Cookie的示例。
# 实现
那么下面就通过一个网络音乐应用的例子(应用详细介绍链接在文末),为大家介绍如何实现用户Token传递,服务器使用Django框架提供的django.contrib.auth模块实现用户登录鉴权。
## 1、用户登录
### 服务端:
获取csrf_token接口:
```
def get_csrf_token(request):
csrf_token = get_token(request)
return JsonResponse({'csrf_token': csrf_token})
```
登录接口:
```
def login_request(request):
username = request.POST.get('username')
password = request.POST.get('password')
print('login from app')
print(request.POST)
# 使用authenticate函数来认证用户
user = authenticate(request, username=username, password=password)
if user is not None:
# 用户认证成功,使用login函数来记录登录状态
login(request, user)
# 设置一个欢迎信息,可以将其改为HttpResponse或重定向
return JsonResponse({'res':"login success!"})
else:
# 认证失败,返回错误信息
return JsonResponse({'res':"login failed!"})
```
### 应用端:
先获取服务器CSRF token,然后使用用户名密码登录。
```
login() {
try {
this.httpRequest.request(ServerConstants.CSRF_URL,
(err: Error, data: http.HttpResponse) => {
if (!err) {
console.info('HttpResponse Result:' + data.result);
const jsonObject: object = JSON.parse(data.result as string);
this.csrfToken = jsonObject['csrf_token'];
this.httpRequest.request(ServerConstants.LOGIN_URL,
{
method: http.RequestMethod.POST,
extraData: 'username=' + this.userName + '&password=' + this.password,
header: {
'content-Type': 'application/x-www-form-urlencoded',
'X-CSRFToken': this.csrfToken,
'Cookie': 'csrftoken=' + this.csrfToken + ';'
},
},
(err: Error, data: http.HttpResponse) => {
if (!err) {
console.info('HttpResponse Result:' + data.result);
console.info('HttpResponse code:' + data.responseCode);
if (200 === data.responseCode) {
this.loginInfo = this.userName
this.loginCookie = data.header['set-cookie'];
}
console.info('HttpResponse type:' + JSON.stringify(data.resultType));
console.info('HttpResponse header:' + JSON.stringify(data.header));
this.getCustomListFromServer();
} else {
console.info('HttpResponse error:' + JSON.stringify(err));
}
});
} else {
console.info('HttpResponse error:' + JSON.stringify(err));
}
});
} catch (err) {
console.info('HttpRequest error:' + JSON.stringify(err));
}
}
```
登录成功后将Cookie保存:`this.loginCookie = data.header['set-cookie'];`
Cookie内容如下:
["csrftoken=VPfo0sQoTzgsRhSrySJsoQZQMxwZWqmAm0Y4L1szUdbwOv41M19tkprs73w6pNrH; expires=Thu, 12 Jun 2025 09:20:42 GMT; Max-Age=31449600; Path=/; SameSite=Lax", "sessionid=e45smklhb4gdaimk3c3pm0kpv1c7u3lq; expires=Thu, 27 Jun 2024 09:20:42 GMT; HttpOnly; Max-Age=1209600; Path=/; SameSite=Lax" ]
## 2、后续请求
### 服务端:
根据用户查询信息的接口:
```
def get_playlists(request):
print(request.user)
playlists = Playlist.objects.filter(user=request.user).values('playlist_name','song').distinct()
result = []
for playlist in playlists:
song = Song.objects.filter(id=playlist.get('song')).values('id', 'name', 'singer','language').first()
combined_queryset = playlist | song
result.append(combined_queryset)
return JsonResponse(result, safe=False)
```
### 应用端:
使用保存的Cookie,放在请求头中,服务端即能从request中获取用户信息。
需要根据请求Cookie进行格式转换:
```
this.loginCookie.map(cookie => {
const parts = cookie.split('=');
return `${parts[0]}=${parts[1]}`;
}).join('; ')
```
完整接口:
```
getCustomListFromServer() {
this.customPlayLists = [];
try {
this.httpRequest.request(ServerConstants.CUSTOM_LIST_URL,
{
method: http.RequestMethod.GET,
header: {
'Cookie': this.loginCookie.map(cookie => {
const parts = cookie.split('=');
return `${parts[0]}=${parts[1]}`;
}).join('; ')
}
},
(err: Error, data: http.HttpResponse) => {
if (!err) {
console.info('HttpResponse getCustomListFromServer Result:' + data.result);
interface PlaylistItem {
playlist_name: string;
song: number;
id: number;
name: string;
singer: string;
language: string;
}
let jsonObject: PlaylistItem[] = JSON.parse(data.result as string);
let groupedByPlaylistName = jsonObject.reduce((accumulator, item) => {
if (!accumulator[item.playlist_name]) {
accumulator[item.playlist_name] = [];
}
accumulator[item.playlist_name].push(item);
return accumulator;
}, {} as Record<string, PlaylistItem[]>);
const keys = Object.keys(groupedByPlaylistName);
keys.forEach((playlistName) => {
console.log(`Playlist: ${playlistName}`);
let aPlayingList: AudioItem[] = Array<AudioItem>();
groupedByPlaylistName[playlistName].forEach((song, index) => {
aPlayingList.push(new AudioItem(song.name, song.singer, song.id.toString()));
});
this.customPlayLists.push(new PlayListData(playlistName, $r('app.media.icon'), aPlayingList.length + '首',
aPlayingList, ''));
});
} else {
console.info('HttpResponse error:' + JSON.stringify(err));
}
});
} catch (err) {
console.info('HttpRequest error:' + JSON.stringify(err));
}
}
```
# 遗留问题
在开发过程中,参考接口文档时,http模块提供了一个缓存接口:
![image.png](
https://forums-obs.openharmony.c ... 9fzqu8vzaec1qiq.png
"image.png")
![image.png](
https://forums-obs.openharmony.c ... 64ag2vbtane6tgk.png
"image.png")按说明理解,应该可以实现自动缓存cookie的功能,但是按示例代码尝试后并不生效,不知和本文所需要的功能是否相同,或者说有bug,有待大家探索。
# 结尾
本例代码是基于我的另一篇网络音乐播放应用开发的,点击:[*应用介绍链接*](
https://forums.openharmony.cn/fo ... thread&tid=2897
"应用介绍链接"),登录代码也会更新到同一个工程中,如有需要可以自行下载。
[/md]
欢迎光临 OpenHarmony开发者论坛 (https://forums.openharmony.cn/)
Powered by Discuz! X3.5