2017-11-12 9 views
0

私はいくつかの新しいフィールドを格納し、DB/UIモデルを別々に保つカスタムユーザーモデルをまとめました。私は、Pythonシェルからユーザーの罰金を作成し、パスワードを検証することができますDjango認証 - 作成されたカスタムユーザーは今やもうログインできません

>python manage.py shell -c " 
    from itemdb.models import MyUser; 
    user = MyUser.objects.create_user('mypass','AD','Joe','Smith','1233','[email protected]'); 
    print user.check_password('mypass'); 
" 
True 

しかし、私は新しい「MyUserと」モデルに私のアプリをポイントすると、私はもう、Webフォーム経由でログインすることができません。

正しいユーザーIDとパスワードを入力してください。両方のフィールドが で大文字小文字を区別することがあります。

必須のフィールドを持つ新しい「ユーザー」テーブルが作成され、ハッシュされたパスワード値が「パスワード」フィールドに格納されています。

"get"、 "save"などのデフォルト関数をオーバーライドできるいくつかの関数を書いています。問題はどこかにあると思います。私の他の推測は、何とかフォームが正しい資格情報を渡していないことです。

私は、モデルを拡張することが最も簡単で分かりやすい方法を知っています。すべての投稿&チュートリアルを読んだことがあります。しかし、私はDBの& UIコードをできるだけ別々にしておきたいと思います。私は近くにいると思う。何が欠けている?なぜ検証がウェブサイト経由で機能していないのかについてのアイデアはありますか?ありがとう。

のPostgres 9.6
パイソン2.7
ジャンゴ1.11

urls.py(切り捨て)

from django.conf.urls import url 
from . import views 
from django.contrib import admin 
from django.contrib.auth import views as auth_views 

app_name= 'itemdb' 

urlpatterns = [ 

    # Authentication/Admin 
    url(r'^login/$', auth_views.login, {'template_name': 'login.html'}, name='login'), 
    url(r'^logout/$', auth_views.logout, {'next_page':'/'}, name='logout'), 
    url(r'^passwordreset/$', auth_views.logout, name='passwordreset'), 

    # Index (i.e. /itemdb/) 
    url(r'^$', views.itemindex, name="itemindex"), 

] 

login.htmlと

{% block content %} 
<h2>Login</h2> 
<form method="post"> 
    {% csrf_token %} 
    {{ form.as_p }} 
    <button type="submit">Login</button> 
</form> 
{% endblock %} 

(切り捨て)settings.py

... 
AUTH_USER_MODEL = 'itemdb.MyUser' # Point to custom user model 
... 

UsersテーブルDDL

CREATE TABLE Users (
    UserId INTEGER NOT NULL, 
    UserType CHAR(2) NOT NULL, 
    FirstName VARCHAR(100) NOT NULL, 
    LastName VARCHAR(100) NOT NULL, 
    PhoneNumber VARCHAR(25), 
    EmailAddress VARCHAR(250), 
    Password VARCHAR(128), 
    Last_Login TIMESTAMPTZ, 
    PRIMARY KEY(UserId) 
); 

SP_IGLGetUser

CREATE OR REPLACE FUNCTION $DB_NAME$Views.SP_IGLGetUser(
    pUserId INTEGER 
) 
RETURNS SETOF $DB_NAME$Views.Users 
AS 
$$ 
BEGIN 
    RETURN QUERY 
    SELECT UserId, UserType, FirstName, LastName, PhoneNumber, EmailAddress, Password, Last_Login 
    FROM $DB_NAME$Views.Users 
    WHERE (UserId = pUserId OR pUserId IS NULL) -- Return single user (if specified, otherwise return all) 
    ; 
END; 
$$ 
LANGUAGE 'plpgsql'; 

models.py

from __future__ import unicode_literals 
from django.db import models 
from UsefulFunctions.dbUtils import * 
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager 
from django.contrib.auth import get_user_model 

# Data model managers (i.e. interface between DB and objects) 
class MyUserManager(BaseUserManager): 

    # Create new user 
    def create_user(self, password, usertype = None, firstname = None, lastname = None, phonenumber = None, emailaddress = None): 
     user = self.model(
      userid=None, 
      usertype=usertype, 
      firstname=firstname, 
      lastname=lastname, 
      phonenumber=phonenumber, 
      emailaddress=self.normalize_email(emailaddress) 
     ) 

     # Save hashed password 
     user.set_password(password) 

     # Save user data and update user object with newly created id 
     result = user.save() 
     user.userid = result[0] 

     return user 

    def get_all(self): 
     users = getDBData(self, 'SP_IGLGetUser(%s)', (None,)) 

     # Return list of user objects 
     return users 

    # Get info for one specific user 
    def get(self, userid): 
     user = getDBData(self, 'SP_IGLGetUser(%s)', (userid,)) 
     return user[0] # First and only row of array 

    def upsertUser(self, myUser): 
     return saveDBData('SP_IGLUpsertUser', 
      (
       myUser.userid, 
       myUser.usertype, 
       myUser.firstname, 
       myUser.lastname, 
       myUser.phonenumber, 
       myUser.emailaddress, 
       myUser.password, 
       myUser.last_login, 
       None 
      ) 
     ) 

    def deleteUser(self, myUser): 
     return deleteDBData('SP_IGLDeleteUser', (myUser.userid, None)) 

# Data models (i.e. tables) 
# Create custom base user 
class MyUser(AbstractBaseUser): 

    # Define attributes (inherited class includes password + last_login fields) 
    userid = models.IntegerField(primary_key=True) # Specify as PK to prevent Django from creating "id" column and for queryset returns (raw) 
    usertype = models.CharField(max_length=2) 
    firstname = models.CharField(max_length=100) 
    lastname = models.CharField(max_length=100) 
    phonenumber = models.CharField(max_length=25) 
    emailaddress = models.CharField(max_length=250) 

    # Define data manager 
    objects = MyUserManager() 

    # Create new constructor (must be passed in correct order) 
    def __init__(self, password = None, last_login = None, userid = None, usertype = None, firstname = None, lastname = None, phonenumber = None, emailaddress = None): 

     # Call parent's init function 
     super(get_user_model(), self).__init__() 

     # Set properties 
     self.userid = userid 
     self.usertype = usertype 
     self.firstname = firstname 
     self.lastname = lastname 
     self.phonenumber = phonenumber 
     self.emailaddress = emailaddress 
     self.last_login = last_login 

    # Class info 
    class Meta: 
     managed = False # Ensure Django doesn't "manage" the table 
     db_table = 'users' # Point to actual DB table 

    # Required fields 
    USERNAME_FIELD = 'userid' # specify how Django recognizes the user 
    EMAIL_FIELD = 'emailaddress' 
    REQUIRED_FIELDS = ['usertype','firstname','lastname'] # email and password are required by default 

    # Required methods 
    def get_full_name(self): 
     return self.firstname + " " + self.lastname + " (" + self.userid + ")" 

    def get_short_name(self): 
     return self.userid 

    def save(self): 
     return MyUser.objects.upsertUser(self) 

    def delete(self): 
     return MyUser.objects.deleteUser(self)  

dbUtils.py

from django.db import connection 
from collections import namedtuple 

# Return all rows from a cursor as named tuples (i.e. rows with field names) 
def namedtuplefetchall(cursor): 
    columns = [col[0] for col in cursor.description] 
    nt_result = namedtuple('Result', columns) 

    return [ 
     nt_result(*row) 
     for row in cursor.fetchall() 
    ] 

def getDBData(myobjects, sp_signature, params): 
    objectlist = [] 

    # Execute raw SQL on object manager and return RawQuerySet object 
    objects = myobjects.raw('select * from ' + sp_signature, params) 

    # Convert RawQuerySet to list of model instances  
    for myobject in objects: 
     objectlist.append(myobject) 

    return objectlist 

def getRawDBData (sp_name, param_list): 
    with connection.cursor() as cursor:   
     cursor.callproc(sp_name, param_list) 
     return_data = namedtuplefetchall(cursor) # Create "rows" 
     cursor.close() 

    return return_data 

def saveDBData(sp_name, param_list): 
    with connection.cursor() as cursor:   
     cursor.callproc(sp_name, param_list) 
     return_data = cursor.fetchone() # Store any output 
     cursor.close() 

    return return_data 

def deleteDBData(sp_name, param_list): 
    return saveDBData(sp_name, param_list) 

更新
問題はパスワードフィールドに空の値を返すされ、get_by_natural_keyに関連しているように見えます。私のテストコール:

>python manage.py shell -c " 
    from itemdb.models import MyUser; 
    user = MyUser.objects.create_user('mypass','AD','c','k','123','email'); 
    print user.userid, user.password; 
    print user.check_password('mypass'); 

    newuser = get_by_natural_key(user.userid) 
    print newuser.check_password('mypass') 
    print newuser.firstname, newuser.password, newuser.emailaddress 
" 
>94 <password_hash_string> 
>True 
>False 
>c email 

create_user()コールは、パスワードの罰金を保存して検証します。

次に、私はget_by_natural_key(user.userid)で新しく作成されたユーザーを再取得しようとします。この呼び出しは、「パスワード」フィールドを除くすべての値が入力されたMyUserオブジェクトを作成します。

私は基礎となるDB関数を直接呼び出し、ハッシュ値を持つ「パスワード」フィールドを実際に返します。

私はいくつかの進歩を遂げましたが、これは私が立ち往生した場所です。私はなぜそれが新しいオブジェクトに "パスワード"の値を渡していないのか分かりません。何か案は?

データフローの問題は、あなたが.created機能からパスワードを設定することができないということです

get_by_natural_key 
    objects.get() 
    getDBData() 
     objects.raw() 
     SP_IGLGetUser() --> Postgres function call 
+0

「MyUser.objects.get_by_natural_key(your_user_id)」とは何ですか? check_password( 'your_password') '出力? – Blender

+0

ありがとう、あなたは正しい方向に私を指摘しました。 MyUser.objects.get_by_natural_key(93).check_password( 'mypass')は** False **を返します。** 私の最新のコメントを見て、あなたの考えを教えてください... – ravioli

+0

'MyUser.objects.get_by_natural_key(93) == MyUser.objects.get(userid = 93) '? 'django.contrib.auth.hashers.check_password(your_user.password、 'actual_password')'は何を返しますか?私はいくつかのブレークポイントを 'django/contrib/auth/base_user.py'に追加し、どこが奇妙になっていくのかを見ていきます。 – Blender

答えて

1

は、あなたが使用する必要があります:

a = User(username='your_username', email='..', ..) 
a.set_password('your_pass') # then you use this for create the password 

理由はDjangoはパスワードをハッシュしなければならないことですその関数を使用します。

+0

ありがとう、私はこの部分をチェックして、それはokを働いているようだ。 – ravioli

+0

あなたを助けた場合はそれを受け入れることを忘れないでください –

関連する問題