iT邦幫忙

0

django沒辦法用request.user

  • 分享至 

  • xImage

我再用django自訂用戶登入之後,沒辦法用request.user
Yes

這是views.py

def get_authenticated_user(request: HttpRequest):
    print(request.user)
    user = request.user
    return JsonResponse({
        "email": user.email,
        "is_staff": user.is_staff,
        "is_active": user.is_active,
        "date_joined": user.date_joined,
        "display_name": user.display_name,
        "mfa_enabled": user.mfa_enabled,
        "discord_id": user.discord_id,
        "discord_name": user.discord_name,
        "discord_tag": user.discord_tag,
        "discord_avatar": user.discord_avatar,
        "discord_public_flags": user.discord_public_flags,
        "discord_flags": user.discord_flags,
        "discord_locale ": user.discord_locale,
    })
def discord_login_redirect(request: HttpRequest):
    code = request.GET.get('code')
    user = exchange_code(code)
    discord_user = authenticate(request, user=user)
    discord_user = list(discord_user).pop()
    print(discord_user)
    login(request, discord_user)
    return redirect("/user")

這是backend.py

class CustomUserAuthenticationBackend(BaseBackend):
    def authenticate(self, request, user) -> CustomUser:
        find_user = CustomUser.objects.filter(email=user['email'])
        if user.get("username") and user.get("discriminator"):
            print('Use discord to auth')
            if len(find_user) == 0:
                print('User was not found. Saving...')
                new_user = CustomUser.objects.create_new_discord_user(user)
                print(new_user)
                return new_user

            # CustomUser.objects.update_user_use_discord(find_user, user)
        print('User was found. Returning...', find_user)
        return find_user

麻煩各位幫我看一下是哪裡出了問題

圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

2 個回答

1
froce
iT邦大師 1 級 ‧ 2022-12-13 23:28:15

https://docs.djangoproject.com/zh-hans/4.1/topics/auth/customizing/#writing-an-authentication-backend

class CustomUserAuthenticationBackend(BaseBackend):
    def authenticate(self, request, user) -> CustomUser:
        # 你用filter傳回的是CustomUser的Queryset,並不是 **單一的CustomUser**。
        find_user = CustomUser.objects.filter(email=user['email'])
        if user.get("username") and user.get("discriminator"):
            print('Use discord to auth')
            if len(find_user) == 0:
                print('User was not found. Saving...')
                new_user = CustomUser.objects.create_new_discord_user(user)
                print(new_user)
                return new_user

            # CustomUser.objects.update_user_use_discord(find_user, user)
        print('User was found. Returning...', find_user)
        # 傳回第一筆
        return find_user.first()

更正確的方式是用官方的例子,用例外捕捉去結合objects.get()去改。

看更多先前的回應...收起先前的回應...

這個我也試過了,request.user也是一樣傳回AnonymousUser...

froce iT邦大師 1 級 ‧ 2022-12-14 08:12:15 檢舉

因為沒你全部的code,所以不能確定,但你的CustomUser應該不是User物件吧?

froce iT邦大師 1 級 ‧ 2022-12-15 10:33:17 檢舉

既然你不肯回答或更進一步放出code,我只好從觀念上回你了。

下面是一個通常的登錄流程,但正常是用POST做,為了範例簡化,我用網址傳參

def testLogin(request, username, password):
    authedUser = auth.authenticate(request, username, password)
    auth.login(request, authedUser)
    return HttpResponse('ok')

Django的登錄分兩步驟,authenticate(認證)和login(登錄),這兩步驟是分開的。

  1. 先對使用者作驗證,authenticate()執行完會回傳一個 django.contrib.auth.models.User 物件
  2. login的時候,接受兩個參數,一個是request,另外一個是 AbstractBaseUser。這步驟才是決定request.user是什麼的關鍵。

所以我建議你該:

  1. 看看你authenticate執行後回傳什麼,用type()去看,一定要是User物件或相關的類,不會是queryset。
  2. 根據 這篇 ,檢查你的使用者密碼是不是經過 hashed。

附帶解釋一下 auth backend的兩個方法是幹嘛用的。

class SettingsBackend(BaseBackend):
    # 這個是在登錄前驗證用,如果一個user物件沒經過任何一個auth backend的這個方法,在login的時候會強制要你指定至少一個
    def authenticate(self, request, username=None, password=None):
        login_valid = (settings.ADMIN_LOGIN == username)
        pwd_valid = check_password(password, settings.ADMIN_PASSWORD)
        if login_valid and pwd_valid:
            try:
                user = User.objects.get(username=username)
            except User.DoesNotExist:
                # Create a new user. There's no need to set a password
                # because only the password from settings.py is checked.
                user = User(username=username)
                user.is_staff = True
                user.is_superuser = True
                user.save()
            return user
        return None

    # 這個是在進入頁面時,從request裡取出request.user的方法
    def get_user(self, user_id):
        try:
            return User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return None

好..不過我發現這個解決有點的...怪?
就只要把model那邊改成CustomUser(AbstractBaseUser, PermissionsMixin)就好了
原因應該是之前繼承的那個使用者模型裡的get_user是直接返回None(對我不知道為什麼

謝謝你

0
hokou
iT邦好手 1 級 ‧ 2022-12-14 11:17:33

看影片上錯誤的部分是 get_authenticated_user()
裡面的 "email": user.email,
也就是說 user = request.user 並沒有取到值,或者不是搜尋表單取得資料後的格式
所以你其他欄位 user.xxx 都是取不到的
建議先往上確認 request.user 的資料格式哪邊出了問題,session 之類的

其他參考資料
django中request.user的由来
request.user哪里来的?
芦苇打代码--django-rest-framework-jwt验证身份AnonymousUser错误

看更多先前的回應...收起先前的回應...

這是session裡的資料
不過它還是傳回AnonymousUser...

https://ithelp.ithome.com.tw/upload/images/20221214/20148005IcAUM7vfcZ.jpg

hokou iT邦好手 1 級 ‧ 2022-12-15 08:18:50 檢舉

所以你的 request.user.is_authenticated 應該是 False
你的圖不是很懂,是指運行過程中都可以 print 出資料,到最後卻出現 AnonymousUser

要不要先把網站暫存的資料全清空,刪除 cookie 或是用無痕之類的試試看

froce iT邦大師 1 級 ‧ 2022-12-15 09:29:51 檢舉

他backend回傳的不是 User物件,當然不會把使用者登入...
不過這取決於他login怎麼寫。

hokou iT邦好手 1 級 ‧ 2022-12-15 13:55:20 檢舉

後來想到,他是想串 discord 的自訂登入,所以可能哪邊沒串好,才會抓不到資料吧

謝謝,不過去翻request.user的那邊之後,發現是我model那邊的問題
改成CustomUser(AbstractBaseUser, PermissionsMixin)
可能是之前繼承的那個使用者模型裡的get_user是直接返回None(我不知道為什麼

謝謝你的參考資料

我要發表回答

立即登入回答