[经验分享] 如何在Http请求中使用Cookie传递用户token,实现登录状态保持。 原创

深开鸿-孙炼 显示全部楼层 发表于 2024-6-14 15:55:58

前言

OpenHarmony作为万物互联的操作系统,网络连接是最基础的能力。其中,有大量的网络应用需要进行用户认证,那么在OpenHarmony的应用开发中,用户登录后,如何在Http请求中使用Cookie传递用户token,实现登录状态保持?

需求

在OpenHarmony中使用@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

image.png按说明理解,应该可以实现自动缓存cookie的功能,但是按示例代码尝试后并不生效,不知和本文所需要的功能是否相同,或者说有bug,有待大家探索。

结尾

本例代码是基于我的另一篇网络音乐播放应用开发的,点击:应用介绍链接,登录代码也会更新到同一个工程中,如有需要可以自行下载。

©著作权归作者所有,转载或内容合作请联系作者

您尚未登录,无法参与评论,登录后可以:
参与开源共建问题交流
认同或收藏高质量问答
获取积分成为开源共建先驱

Copyright   ©2023  OpenHarmony开发者论坛  京ICP备2020036654号-3 |技术支持 Discuz!

返回顶部