Lecturer:Yan
Django
User
-
Login
-
Logout
-
Registration
-
Social Login
Outline
Check
使用 django.contrib 套件中的 auth app
確認裡面有 'django.contrib.auth'
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth', # 確認有這句
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'restaurants',
]
打開 mysite/settings.py
一樣在 mysite/settings.py
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware', # 確認有這句
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
確認裡面有
'django.contrib.auth.middleware.AuthenticationMiddleware'
修改 urls.py
# 確認這些都有引入
from django.contrib import admin
from django.urls import path, include
...
urlpatterns = [
...
path('accounts/', include('django.contrib.auth.urls')), # 新增
]
路徑:mysite / urls.py
django.contrib.auth.urls
from django.contrib.auth import views
from django.urls import path
urlpatterns = [
path('login/', views.LoginView.as_view(), name='login'),
path('logout/', views.LogoutView.as_view(), name='logout'),
path('password_change/', views.PasswordChangeView.as_view(), name='password_change'),
path('password_change/done/', views.PasswordChangeDoneView.as_view(), name='password_change_done'),
path('password_reset/', views.PasswordResetView.as_view(), name='password_reset'),
path('password_reset/done/', views.PasswordResetDoneView.as_view(), name='password_reset_done'),
path('reset/<uidb64>/<token>/', views.PasswordResetConfirmView.as_view(), name='password_reset_confirm'),
path('reset/done/', views.PasswordResetCompleteView.as_view(), name='password_reset_complete'),
]
這是它的原始碼
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']
因此當我們定義好了
path('logout/', views.LogoutView.as_view(), name='logout')
就是額外新增了以下這些路徑可以使用
Create Login page
先在 mysite / templates 中新建資料夾 registration
目前在 template 資料夾中的結構
├── base.html
├── home.html
└── registration (新增資料夾)
└── login.html (新增檔案)
新建 login.html
{% extends "base.html" %}
{% block content %}
<h1>Login</h1>
<form action="{% url 'login' %}" method="post" class="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">
<a href="{% url 'password_reset' %}">忘記密碼?</a>
</form>
{% endblock %}
路徑:mysite / templates / registration / login.html
login.html 的另一種寫法
{% extends "base.html" %}
{% block content %}
<h1>Login</h1>
<form action="{% url 'login' %}" method="post" class="login">
{% csrf_token %}
<table>
{{ form.as_table }}
</table>
<input type="submit" value="login">
<a href="{% url 'password_reset' %}">忘記密碼?</a>
</form>
{% endblock %}
檔案路徑:mysite / templates / registration / login.html
這邊用了 {{ form.as_table }} 來代替了前面一串
<table>
{{ form.as_table }}
</table>
<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>
要來 解釋程式碼啦
<form action="{% url 'login' %}" method="post" class="login">
{% url '字串' %}
Django 會將這裡的字串對應到符合 name 參數的 url pattern
例如 {% url 'login' %} 即為對應到
path('accounts/login/', views.LoginView.as_view())
<a href="{% url 'password_reset' %}">忘記密碼?</a>
所以這裡的 {% url 'password_reset' %} 就會對應到
重設密碼的 url pattern
{% csrf_token %}
為了防範 CSRF 攻擊因此加上這行
這樣當你的網頁就會產生一串 token
如果想知道 CSRF 可以參考土豆的 slides
繼續寫程式吧
修改 view.py
def login(request):
if request.user.is_authenticated:
return redirect('/')
username = request.POST.get('username', '')
password = request.POST.get('password', '')
user = auth.authenticate(username=username, password=password)
if user is not None and user.is_active:
auth.login(request, user)
return redirect('/')
else:
return render(request, 'login.html', locals())
路徑:mysite /blog/ view.py
Create Logout page
修改 view.py
def logout(request):
auth.logout(request)
return redirect('/')
路徑:mysite / blog/ view.py
Create Registration page
新建 register.html
{% extends 'base.html' %}
{% block title %}
<h1>Register Page</h1>
{% endblock title %}
{% block content %}
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
{% for field in form %}
{{ field.errors }}
{% endfor %}
<button type="submit">送出</button>
</form>
{% endblock content %}
路徑:mysite / templates / registration / register.html
修改 view.py
from django.contrib.auth.forms import UserCreationForm
def register(request):
if request.method == 'POST':
form = UserCreationForm(request.POST)
print("Errors", form.errors)
if form.is_valid():
form.save()
return redirect('/')
else:
return render(request, 'registration/register.html', {'form':form})
else:
form = UserCreationForm()
context = {'form': form}
return render(request, 'registration/register.html', context)
路徑:mysite / blog / view.py
修改 urls.py
# 新增 register
from trips.views import home, post_detail..., register
urlpatterns = [
...
path('register/', register, name='register'), # 新增
]
路徑:mysite / urls.py
修改 settings.py
# 新增
LOGIN_REDIRECT_URL = '/home/'
LOGOUT_REDIRECT_URL = '/home/'
路徑:mysite / mysite / settings.py
Modify Basic page
修改 base.html
<nav class="navbar">
<a class="navbar-brand" href="/home">My blog</a>
<a class="navbar-brand" href="/showImg">My Image</a>
...
<!--修改-->
{% if request.user.is_superuser %}
<a class="navbar-brand" href="/admin">Admin</a>
<a class="navbar-brand" href="{% url 'logout' %}">Logout</a>
{% elif request.user.is_authenticated %}
<a class="navbar-brand" href="{% url 'logout' %}">Logout</a>
{% else %}
<a class="navbar-brand" href="{% url 'login' %}">Login</a>
<a class="navbar-brand" href="/register">Sign up</a>
{% endif %}
<!--到這邊-->
</nav>
路徑:mysite / templates / base.html
所以 剛剛打了些什麼
{% if request.user.is_superuser %}
{% elif request.user.is_authenticated %}
.is_superuser
用戶是否認證過,若有回傳True
若為AnonymousUser物件,則回傳False
.is_authenticated
用戶是否為超級使用者
{% if request.user.is_superuser %}
<a class="navbar-brand" href="/admin">Admin</a>
<a class="navbar-brand" href="{% url 'logout' %}">Logout</a>
{% elif request.user.is_authenticated %}
<a class="navbar-brand" href="{% url 'logout' %}">Logout</a>
{% else %}
<a class="navbar-brand" href="{% url 'login' %}">Login</a>
<a class="navbar-brand" href="/register">Sign up</a>
{% endif %}
補充一下 User 物件中的 Attribute
補充一下 User 物件中的 Method
Modify Home page
修改 home.html
{% block content %}
<h2>Hello! this is my blog</h2>
<!--修改 user.is_authenticated的部分-->
{% if request.user.is_superuser %}
<p>Welcome, {{ user.username }}</p>
<a href="{% url 'post_new' %}"><span> 新增文章 </span></a>
{% elif request.user.is_authenticated %}
<p>Welcome, {{ user.username }}</p>
...
{% empty %}
<p>敬請期待</p>
{% endfor %}
</div>
{% else %}
<p>登入後即可查看文章</p>
{% endif %}
{% endblock %}
路徑:mysite / templates / home.html
寫好了就來測試一下吧
$ python manage.py runserver
如果你有寫 shell 的話
$ runserver.sh
Update to Heroku
登入 Heroku
$ Heroku login
上傳檔案
$ git add .
$ git commit -m "你想留下的訊息"
$ git push heroku master
請確定自己進到要上傳的資料夾裡了
確定一下 Heroku 上的網頁能運作
$ heroku open
出現 Not Found 的時候,記得確認一下網址是否加了 /home
恭喜你完成 登入登出跟註冊了
Social Login - Github
安裝 social-auth-app-django
$ pip install social-auth-app-django
修改 requirements.txt
...
social-auth-app-django==3.4.0 # 新增
修改 login.html
<!--新增超連結-->
<a href="{% url 'social:begin' 'github' %}">Github 登入</a>
路徑:mysite / templates / registration / login.html
修改 urls.py
urlpatterns = [
...
# 新增
path('', include('social_django.urls', namespace='social')),
]
路徑:mysite / urls.py
修改 settings.py
INSTALLED_APPS = [
...
# 新增
'social_django',
]
路徑:mysite / mysite / settings.py
繼續修改 settings.py
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'social_django.context_processors.backends', # 新增
'social_django.context_processors.login_redirect', #新增
],
},
},
]
路徑:mysite / mysite / settings.py
還是在修改 settings.py
# 新增
AUTHENTICATION_BACKENDS = (
'social_core.backends.github.GithubOAuth2',
'django.contrib.auth.backends.ModelBackend',
)
SOCIAL_AUTH_URL_NAMESPACE = 'social'
SOCIAL_AUTH_GITHUB_USE_OPENID_AS_USERNAME = True
# 登入成功後轉址
SOCIAL_AUTH_LOGIN_REDIRECT_URL = '/home'
路徑:mysite / mysite / settings.py
Github OAuth
先去申請開放授權(OAuth)
OAuth 簡介
Open Authorization
透過這種協定,使用者可以在不透露帳號密碼的情況下,
授權第三方網路應用服務使用(或登入)原本的網路服務
申請好後就能獲得 Client ID 和 Client Secret
修改 settings.py
# 新增
SOCIAL_AUTH_GITHUB_KEY = '你的 Client ID'
SOCIAL_AUTH_GITHUB_SECRET = '你的 Client Secret'
路徑:mysite / mysite / settings.py
同步一下資料庫
$ cd 到 manage.py 所在位置
$ python manage.py migrate
本地端測試
$ python manage.py runserver
如果你有寫 shell 的話
$ runserver.sh
Lab - Google Login
Modify CSS
自由發揮時間
(因為我覺得內建有點醜
(這是為了沒 bug 的人找的工作
Update to Heroku
如果你還沒登入 Heroku 的話
$ Heroku login
上傳檔案
$ git add .
$ git commit -m "你想留下的訊息"
$ git push heroku master
請確定自己進到要上傳的資料夾裡了
接著初始化資料庫
$ heroku run python mysite/manage.py migrate
放上去的話記得要改這邊的網址呦
確定一下 Heroku 上的網頁能運作
$ heroku open
出現 Not Found 的時候,記得確認一下網址是否加了 /home
Thanks for listening.
References
- DOKELUNG. (2015). Django筆記(10) - 用戶的登入與登出. Retrieved from http://dokelung-blog.logdown.com/posts/234437-django-notes-10-users-login-and-logout
- BY. (2018). Day28 : Django auth - 登入/登出. Retrieved from https://ithelp.ithome.com.tw/articles/10206063
- BY. (2018). Day29 : Django 註冊. Retrieved from https://ithelp.ithome.com.tw/articles/10206355
- itread01. (2018). django實現github第三方本地登錄. Retrieved from https://www.itread01.com/content/1536238613.html
兩堂課帶你入門番外篇 Django - User
By oneone
兩堂課帶你入門番外篇 Django - User
【SIRLA 2021 對外課程】雖然寫著兩堂課,但其實是(目標)兩堂課帶你入門,第三堂課剩下的時間就來談談如何第三方登入吧
- 44