赞
踩
Django身份验证系统包括了身份验证和授权两个功能。
身份验证验证用户是谁
授权是一个被验证过的用户允许做些什么
身份验证系统包括:
# filename: setting.py
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'file_sync.apps.FileSyncConfig',
'note.apps.NoteConfig',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware', #HERE
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware', #HERE
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
Django身份验证同时提供身份验证和授权,通常称为身份验证系统,因为这些功能在某种程度上是耦合的。
##user 对象(user objects),每个用户的属性
User 对象是验证系统的核心,通常代表了进入你网站的用户,并且用来管理他们比如限制进入,限制内容等。在Django中只存在一个user 类,"superusers"或者admin “staff” 的用户只是user对象中带有特殊属性的对象,并不是单独的类。
默认的user对象属性:
from django.contrib.auth.models import User
user = User.objects.create_user('john', 'lennon@thebeatles.com', 'johnpassword')
使用命令行
$ python manage.py createsuperuser --username=joe --email=joe@example.com
如果不加–username和–email,会提示你输入
Django没有显式密码,密码会被hash。改变密码的方式:
from django.contrub.auth.models import User
u = User.objects.get(username='john')
u.set_password('new password')
u.save()
使用aurhenticate()去验证资格,默认使用username和password去验证。如果验证合法,返回User对象,如果不合法或者后端产生权限禁止,该函数返回None。example:
from django.contrib.auth import authenticate
user = authenticate(username='john', password='secret')
if user is not None:
# A backend authenticated the credentials
else:
# No backend authenticated the credentials
request是一个可选项,给验证后端传入HttpRequest。
Note: 这种验证方法有些低级,除非是为你自己写的登录验证,否则请使用LoginView()
先验证身份,在使用login(User)进行登录,Django后台会自动处理cookie
def login_post(request):
username = request.POST['username']
password = request.POST['password']
user = authenticate(request, username=username,password=password)
if user is not None :
login(request,user)
#Redirect to a success page.
#return render(request,'file_sync/upload.html')
return HttpResponseRedirect(reverse('file_sync:upload'))
else:
return HttpResponse('login failed!')
def logout_view(request):
logout(request)
# return render(request,'file_sync/login.html')
return HttpResponseRedirect(reverse('file_sync:loginview'))
Note: 重定向函数是HttpRespinseRedirect(),函数render是一个shortcuts,快捷函数,集成了打开请求,处理要返回的上下文(context)等。不可以用作网页跳转。使用rendr虽然会有跳转的作用,但是会缺少网页渲染所需要的数据,除非你在这个view中将数据处理后传过去。
如果此页面需要登录,则跳转到登录界面,并且携带next参数对登录页面进行get请求。
例如:
当前页面为https://www.mysite.com/file_sync/
该页面需要登录查看,该页面的view前面有@login_required修饰,但是你没有登录,则会跳转到登录页面。如果你的登录页面位于/accounts/login/,那么你跳转的页面位置为
https://www.mysite.com/accounts/login/?next=/file_sync/
这里的next的参数是上一个页面的绝对地址,并且添加得到get请求中。在你处理登录界面的时候,需要对next参数进行特殊处理
def loginview(request): if 'GET' == request.method: #GET页面请求 try : #尝试获取请求中GET的next参数,并且构成上写文 next=request.GET['next'] #注意这里用try,因为当请求不包含next时,比如直接访问登录页面,GET['next']并不存在,会发生错误 context = { 'next':next } except : context={ 'next':'/index/' #如果没有next,制定next为主页面 } return render(request,'file_sync/login.html',context) if 'POST'== request.method: #密码验证 前端需要传来三个参数 username = request.POST['username'] password = request.POST['password'] next = request.POST['next'] user = authenticate(request, username=username, password=password) if user is not None: login(request, user) #redirect to a success page. return HttpResponseRedirect(next) else: return HttpResponse('login failed!')
该页面前端
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Login</title> </head> <body> <div style="margin: 15% 40%;"> <h1>欢迎登录!</h1> <form action="/file_sync/login/" method="post" enctype="multipart/form-data"> <p> <label for="id_username">用户名:</label> <input type="text" id="id_username" name="username" placeholder="用户名" autofocus required /> </p> <p> <label for="id_password">密码:</label> <input type="password" id="id_password" placeholder="密码" name="password" required > </p> <input type="submit" value="确定"> <input type="hidden" name="next" value="{{ next }}"> </form> </div> </body> </html>
Django提供了viewLogin,只需要自己写前端页面,后端逻辑不用自己处理。当不复杂的时候推荐使用这种方法。
urlpatterns = [
path('admin/', admin.site.urls),
path('file_sync/',include('file_sync.urls')),
path('note/',include('note.urls')),
#path('', include('file_sync.urls')),
path('accounts/', include('django.contrib.auth.urls'))
]
将会包含以下:
accounts/login/ [name='login']
accounts/logout/ [name='logout']
accounts/password_change/ [name='password_change']
accounts/password_change/done/ [name='password_change_done']
accounts/password_reset/ [name='password_reset']
accounts/password_reset/done/ [name='password_reset_done']
accounts/reset/<uidb64>/<token>/ [name='password_reset_confirm']
accounts/reset/done/ [name='password_reset_complete']
python3 startapp registration
cd registration
mkdir templates && cd templates
mkdir registration
大致目录结构
registration/
├── admin.py
├── apps.py
├── __init__.py
├── migrations
│ └── __init__.py
├── models.py
├── templates
│ └── registration
│ └── login.html
├── tests.py
└── views.py
Warning
If you enable redirect_authenticated_user, other websites will be able to determine if their visitors are authenticated on your site by requesting redirect URLs to image files on your website. To avoid this “social media fingerprinting” information leakage, host all images and your favicon on a separate domain.
Enabling redirect_authenticated_user can also result in a redirect loop when using the permission_required() decorator unless the raise_exception parameter is used.
重新定位登录网页位置为myapp/login.html
from django.contrib.auth import views as auth_views
path('accounts/login',auth_views.LoginView.as_view(template_name='myapp/login.html'))
指定登录重定向页面名称,默认名是next,给为nextone
from django.contrib.auth import views as auth_views
path('accounts/login',auth_views.LoginView.as_view(redirect_filed_name='nextone'))
如果没有特殊要求,可以都不改。
这个模板将会收到view传来的四个参数:
{% block content %} {% if form.errors %} <p>Your username and passsword didn't match</p> {% endif %} {% if next %} {% if user.is_authenticated %} <p>Your account doesn't have access to this page</p> <% else %> <p>Please login to see this page</p> {% endif %} {% endif %} <form method="post" action="/accounts/login/"> {% csrf_token %} <table> <tr> <td> {{ form.username.label_tag }}</td> <td> {{ form.username }}</td> </tr> <tr> <td>{{ form.password.label_tag }}</td> <td>{{ form.password }}</td> </tr> </table> <input type="submit" value="login"> <input type="hidden" name="next" value="{{ next }}"> </form> {% endblock %}
在setting中加入
LOGIN_REDIRECT_URL = '/file_sync/upload/' # login success redirect to
LOGOUT_REDIRECT_URL = '/accounts/login/' #logout and redirect to
LOGIN_URL = '/accounts/login/' # 为了logout then login
##其他有用的函数
如果某个view需要登录或者验证才能使用,则用以下语法
if request.user.is_authenticated:
# Do something for authenticated users.
...
else:
# Do something for anonymous users.
from django.contrib.auth.decorators import login_required
@login_required
def my_view(request):
...
login_reqired() 做了如下
from django.contrib.auth.decorators import login_required
@login_required(redirect_field_name='my_redirect_field')
def my_view(request):
...
举例2,提供登录的url
from django.contrib.auth.decorators import login_required
@login_required(login_url='/accounts/login/')
def my_view(request):
...
from django.contrib.auth.mixins import LoginRequiredMixin
class MyView(LoginRequiredMixin, View):
login_url = '/login/'
redirect_field_name = 'redirect_to'
这个类的所有函数,对于未登录的用户都将重定向到登录界面或者403禁止进面
例如,只有邮箱结尾是‘@example.com’的用户才有权限进入
直接使用:
from django.shortcuts import redirect
def my_view(request):
if not request.user.email.endswith('@example.com'):
return redirect('/login/?next=%s' % request.path)
# ...
使用装饰器:
from django.contrib.auth.decorators import user_passes_test
def email_check(user):
return user.email.endswith('@example.com')
@user_passes_test(email_check)
def my_view(request):
...
user_passes_test(*, login_url,redirect_filed_name)
Note user_passer_test 不会自动检测用户是匿名用户
在该类中需要重写test_func()方法提供检测
from django.contrib.auth.mixins import UserPassesTestMixin
class MyView(UserPassesTestMixin, View):
def test_func(self):
return self.request.user.email.endswith('@example.com')
你也可以重写get_test_func()方法,以使mixin对其检查使用不同名称的函数(而不是test_func())。
具体见官网文档
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。