私はいくつかの新しいフィールドを格納し、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
「MyUser.objects.get_by_natural_key(your_user_id)」とは何ですか? check_password( 'your_password') '出力? – Blender
ありがとう、あなたは正しい方向に私を指摘しました。 MyUser.objects.get_by_natural_key(93).check_password( 'mypass')は** False **を返します。** 私の最新のコメントを見て、あなたの考えを教えてください... – ravioli
'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