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