大家好,我是長風青雲。
今天是鐵人賽的第七天,嗯?居然已經一個禮拜了?!
(如果三十天後我還沒講完我要講的,我還是會繼續發文的 ^w^ )
上次說,我們要做註冊和登入登出~
但其實吧,我一開始看著flask-login的時候完全霧煞煞,所以一開始我就走向了另一條道路──session。
那session是什麼呢?
簡單來說session是個可以儲存資料的地方,而且因為他是建立在cookie上的,所以當使用者登入的時候,與其他電腦並沒有關係。
(遙想我一開始,居然設一個login的variable,結果我發現……我用別台電腦,他認為我還在登入,他根本不知道使用者是誰阿QwQ)→走過歪路的我
那首先我們HTML先做好吧~
(register.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" type="text/css" href="{{url_for('static',filename='css/nav_bar.css')}}">
<title>ironman album</title>
</head>
<style>
body{
margin: 0;
font-family: Arial, Helvetica, sans-serif;
}
table{
background-color:plum;
border-radius:5px;
padding-bottom: 10px;
padding-top: 15px;
padding-right: 10px;
margin-top:20px;
width:70%;
}
input{
font-size: initial;
}
span {
background-color:#FFC8B4;
box-shadow:1px 1px 3px red;
margin-right:8px;
}
@media screen and (max-width: 400px){
table{
width:90%;
}
}
.button {
border:0;
background-color:darkviolet;
color:#fff;
border-radius:20px;
cursor:pointer;
width:90px;
height:30px;
}
.button:hover{
color:black;
background-color: lavender;
}
</style>
<body>
<form method="post">
<ul class="computer" id="topnav">
<li><a href="../" class="active">首頁</a></li>
<li><a href="../album">相簿</a></li>
<li><a href="../register">註冊</a></li>
<li><a href="../login">登入</a></li>
<li style="float:right"><a href="javascript:void(0);" class="icon" onclick="myFunction()"><i class="fa fa-bars"></i></a></li>
</ul>
<div style="padding-top: 100px">
<table align="center">
<tr>
<td colspan="2" align="right"><span>{{alert}}</span></td>
</tr>
<tr>
<th width="15%">account</th>
<td><input class="w3-input w3-border w3-round-large" type='text' name="userid" value={{id}}></td>
</tr>
<tr>
<th>password</th>
<td><input class="w3-input w3-border w3-round-large" type='password' name="userpw" value={{pw}}></td>
</tr>
<tr>
<th>Nick Name</th>
<td><input class="w3-input w3-border w3-round-large" type='text' name="username" value={{nick}}></td>
</tr>
<tr>
<td colspan="2" align="right"><input class="button" value="送出" type='submit' name="send"></td>
</tr>
</table>
</div>
</form>
<script>
function myFunction() {
var x = document.getElementById("topnav");
if (x.className === "computer") {
x.className = "phone";
} else {
x.className = "computer";
}
}
</script>
</body>
</html>
有些前面說過的,我就不多做贅述了~
這裡我引用了w3-school的css,因為我覺得他的input做的滿好看的,所以我就link進來,然後在input加上對應的class。
然後table
的部分,border-radius
是讓他外框是圓弧的~多弧就看你們決定囉~input
的font-size:initial
,是為了避免使用手機時他會跟著輸入框一起放大。span
的box-shadow
,就是設定他的陰影~button
那邊的cusor:pointer
是指滑鼠滑到那裡,呈現的樣子。
(login.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" type="text/css" href="{{url_for('static',filename='css/nav_bar.css')}}">
<title>ironman album</title>
</head>
<style>
body{
margin: 0;
font-family: Arial, Helvetica, sans-serif;
}
table{
background-color:plum;
border-radius:5px;
padding-bottom: 10px;
padding-top: 15px;
padding-right: 10px;
margin-top:20px;
width:70%;
}
input{
font-size: initial;
}
span {
background-color:#FFC8B4;
box-shadow:1px 1px 3px red;
margin-right:8px;
}
@media screen and (max-width: 400px){
table{
width:90%;
}
}
.button {
border:0;
background-color:darkviolet;
color:#fff;
border-radius:20px;
cursor:pointer;
width:90px;
height:30px;
}
.button:hover{
color:black;
background-color: lavender;
}
</style>
<body>
<ul class="computer" id="topnav">
<li><a href="../" class="active">首頁</a></li>
<li><a href="../album">相簿</a></li>
<li><a href="../register">註冊</a></li>
<li><a href="../login">登入</a></li>
<li style="float:right"><a href="javascript:void(0);" class="icon" onclick="myFunction()"><i class="fa fa-bars"></i></a></li>
</ul>
<form method="post">
<div style="padding-top: 100px">
<table align="center">
<tr>
<td colspan="2" align="right"><span>{{alert}}</span></td>
</tr>
<tr>
<th width="15%">account</th>
<td><input class="w3-input w3-border w3-round-large" type='text' name="userid" value={{id}}></td>
</tr>
<tr>
<th>password</th>
<td><input class="w3-input w3-border w3-round-large" type='password' name="userpw" value={{pw}}></td>
</tr>
<tr>
<td colspan="2" align="right"><input class="button" value="登入" type='submit' name="send"></td>
</tr>
</table>
</div>
</form>
<script>
function myFunction() {
var x = document.getElementById("topnav");
if (x.className === "computer") {
x.className = "phone";
} else {
x.className = "computer";
}
}
</script>
</body>
</html>
(logout.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" type="text/css" href="{{url_for('static',filename='css/nav_bar.css')}}">
<title>ironman album</title>
</head>
<style>
body{
margin: 0;
font-family: Arial, Helvetica, sans-serif;
}
table{
background-color:plum;
border-radius:5px;
padding-bottom: 10px;
padding-top: 15px;
padding-right: 10px;
margin-top:20px;
width:70%;
}
input{
font-size: initial;
}
span {
background-color:#FFC8B4;
box-shadow:1px 1px 3px red;
margin-right:8px;
}
@media screen and (max-width: 400px){
table{
width:90%;
}
}
.button {
border:0;
background-color:darkviolet;
color:#fff;
border-radius:20px;
cursor:pointer;
width:90px;
height:30px;
}
.button:hover{
color:black;
background-color: lavender;
}
</style>
<body>
<form method="post">
<ul class="computer" id="topnav">
<li><a href="../" class="active">首頁</a></li>
<li><a href="../album">相簿</a></li>
<li><a href="../upload">上傳</a></li>
<li><a href="../logout">登出</a></li>
<li style="float:right"><a href="javascript:void(0);" class="icon" onclick="myFunction()"><i class="fa fa-bars"></i></a></li>
</ul>
<div style="padding-top: 80px;padding-left:20px">
<h2>確認登出嗎?</h2>
<p> </p>
<p><input class="button" value="確定" type='submit' name="send">
<input class="button" value="取消" type='submit' name="send"></p>
</div>
</form>
<script>
function myFunction() {
var x = document.getElementById("topnav");
if (x.className === "computer") {
x.className = "phone";
} else {
x.className = "computer";
}
}
</script>
</body>
</html>
我看了看,login和logout沒有什麼能說的,該說的都說過了,所以就直接放上來,然後我們來進入我們的後台吧~
在此之前,不知道大家有沒有聽過json?
Json是一種儲存資料的格式,也可以是個檔名。因為方便使用,所以廣泛用在API上。
在這裡,我會直接把他當作資料庫來使用 ^w^
(如果json其實不能當資料庫的話,比如會有什麼資安問題呀,可以告訴我喔!
因為我目前就是不知道可不可以,然後又因為方便,就直接默認可以這樣做了)
我們儲存註冊者資料的地方就是使用json檔,所以請你打開一個編輯器,輸入{}
然後儲存成member.json,位置與app.py同層。
接著開始寫我們的app.py,剛才我說過,我們要使用session還有json。
所以要先做import的動作from flask import session
還有import json
接下來session其實是需要一個密鑰的,雖然其實我不知道他實際用在哪裡XD
但請你還是加在app=Flask(__name__)
下面,像是這樣
app=Flask(__name__)
app.secret_key= b'你的密鑰'
密鑰部分最好是亂碼,而且這部分既然都被稱為『密』鑰了,就代表他是一個secret的東西,所以要保護好他不要被別人知道喔~
@app.route('/register',methods=['POST','GET'])
def register():
with open('./member.json','r') as file_object:
member = json.load(file_object)
if request.method=='POST':
if request.values['send']=='送出':
if request.values['userid'] in member:
for find in member:
if member[find]['nick']==request.values['username']:
return render_template('register.html',alert='this account and nickname are used.')
return render_template('register.html',alert='this account is used.',nick=request.values['username'])
else:
for find in member:
if member[find]['nick']==request.values['username']:
return render_template('register.html',alert='this nickname are used.',id=request.values['userid'],pw=request.values['userpw'])
member[request.values['userid']]={'password':request.values['userpw'],'nick':request.values['username']}
with open('./member.json','w') as f:
json.dump(member, f)
return render_template('index.html')
return render_template('register.html')
在這裡,我設計的member長像大概是{ “帳號”:{‘password’:“密碼”,nick:”暱稱”}},帳號是我們的key,可是我腦子一抽,覺得如果同一個名稱的話不是就會搞混誰是誰誰誰了嗎?所以暱稱我也把他設計為只能有一個。
確認userid和username都沒有重複後,就會將他加入到member.json裡面。
「大部分的註冊不是需要經過驗證嗎?」
對,你沒想錯,但這部分是我之後的實例才會說~而且到時候我會把網頁放到虛擬機上跑給大家看 ^w^
因為這是我們的第一個實例,所以一開始我幾乎什麼都沒做╮(╯∀╰)╭
喔對了,網路相簿就是我姊叫我寫的專案,所以既然是『姊姊叫你寫』的......
可想而知不會太用心d(`・∀・)b
這樣在註冊後你的member就會改變成
{"yueh860304": {"password": "不告訴你", "nick": "Charlotte"}, "yueh970304": {"password": "不告訴你", "nick": "Longwind"}}
password我自己是打我慣用的密碼啦~所以我就把它改為『不告訴你』,並不是真的會長這樣子喔!
然後你login和logout的部分就是:
@app.route('/login',methods=['GET','POST'])
def login():
if request.method== 'POST' :
with open('./member.json','r') as file_object:
member = json.load(file_object)
if request.values['userid'] in member:
if member[request.values['userid']]['password']==request.values['userpw']:
session['username']=request.values['userid']
return redirect ( url_for ( 'index' ))
else:
return render_template('login.html',alert="Your password is wrong, please check again!")
else:
return render_template('login.html',alert="Your account is unregistered.")
return render_template('login.html')
@app.route('/logout',methods=['GET','POST'])
def logout ():
if request.method=='POST':
if request.values['send']=='確定':
session.pop('username',None)
return redirect(url_for('index'))
return render_template('logout.html')
login就是經過比對確認有這個帳號,然後帳號密碼相同的話就會把你的userid加入session session['username']=request.values['userid']
logout則是你確認登出後,會把名為在session裡key為username的資料清空session.pop('username',None)
現在來看個影片吧~
有沒有覺得很開心~這樣註冊和登入登出的部分做好後,我們要開始著手上傳的部分。
大家明天見唷~
哈囉~
還滿開心看到有人在玩 Flask 的,Flask 是我目前滿喜歡的 Python Web Framework 之一。
底下有幾項是我個人使用了四年 Flask 的拙見,希望對你有幫助。
@login_required
、login_user
、logout_user
等等)ItsDangerous
基本上就在處理這塊,所以才要設定 secret_key加油~ 撐住這三十天
謝謝你告訴我~我在使用JSON當資料庫的時候心裡的確有點慌...
可能潛意識知道資安上會出問題。(可能密碼學的老師會跳出來打我
其實我到現在還沒使用過真正的資料庫...(一直用各種方式代替
這幾天我研究看看,如果我能力夠的話我就把後面的實例寫成資料庫的樣子~
而看你這麼推Flask-login....我決定把他放進後面的實例當中
(之前因為用session規避掉這個問題,所以沒有去學習,還想著鐵人賽結束之後再去看)
而相簿就算了...我覺得我寫他寫太久,暫時不想更動他。
(而且不是因為自己想要才寫的東西,好像比較沒有愛?)
我會努力撐過30天的 d(^w^ )
我可是對我奶奶說要把連續30天的獎牌送給她呢~