要求:
上代碼:
服務(wù)端:
import redis
import re
import json
import time
import cgi
from redis import StrictRedis, ConnectionPool
from flask import Flask,jsonify,request
import requests
app = Flask(__name__)
def insert_into_redis(shorturl,longurl):
print("----come to function--- insert_into_redis(shorturl,longurl)")
# 如果含義為插入,則做插入操作
pool = ConnectionPool(host='localhost', port=6379, db=0, decode_responses=True)
# redis 取出的結(jié)果默認(rèn)是字節(jié),我們可以設(shè)定 decode_responses=True 改成字符串。
r = StrictRedis(connection_pool=pool)
string = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
r.hset("shorttolong",shorturl, json.dumps({"longurl": longurl,"visittime": [], "creattime":string}))
r.hset("longtoshort",longurl,shorturl)
print("Info: The value {0} is inserted".format(shorturl))
return 1
def check_if_exist(longurl):
print("----come to function--- check_if_exist(longurl)")
pool = ConnectionPool(host='localhost', port=6379, db=0, decode_responses=True)
r = StrictRedis(connection_pool=pool)
# 判斷是否存在,如果存在則返回1
if r.hexists("longtoshort",longurl):
result = 1
else:
result = 0
return result
def check_shorturl_if_exist(shorturl):
print("----come to function--- check_shorturl_if_exist(shorturl)")
pool = ConnectionPool(host='localhost', port=6379, db=0, decode_responses=True)
r = StrictRedis(connection_pool=pool)
# 判斷是否存在,如果存在則返回1
if r.hexists("shorttolong",shorturl):
result = 1
else:
result = 0
return result
def get_longurl(shorturl):
print("----come to function--- get_longurl(shorturl)")
pool = ConnectionPool(host='localhost', port=6379, db=0, decode_responses=True)
r = StrictRedis(connection_pool=pool)
# 判斷是否存在,如果存在則返回1
longurljson = r.hmget("shorttolong",shorturl)
longurl = json.loads(longurljson[0])["longurl"]
#print(longurljson)
#print(longurl)
return longurl
def update_jumptime(shorturl):
print("----come to function--- update_jumptime(shorturl)")
pool = ConnectionPool(host='localhost', port=6379, db=0, decode_responses=True)
r = StrictRedis(connection_pool=pool)
longurljson = r.hmget("shorttolong", shorturl)
dic1 = json.loads(longurljson[0])
list1 = dic1["visittime"]
#print(list1)
string = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
list1.append(string)
dic1["visittime"] = list1
r.hset("shorttolong", shorturl, json.dumps(dic1))
print("info: update the visittime of the {0} success".format(shorturl))
return 1
"""
0.判斷長(zhǎng)鏈接是否已經(jīng)存在
在用戶端進(jìn)行創(chuàng)建的時(shí)候,要檢查長(zhǎng)鏈接是否已經(jīng)在服務(wù)端存在了,如果存在應(yīng)該忽略。
如何確定服務(wù)端存在,通過post 接口來查詢。
檢查長(zhǎng)URL是否有效:通過checkurl(longurl)函數(shù),當(dāng)longurl 已經(jīng)存在,
返回json字段{'result':1},不存在則否則返回{'result':0}
"""
@app.route('/api/checkurl', methods=['POST'])
def check_url():
print("----come to function--- check_url() /api/checkurl logic")
longurl = request.json['longurl']
result = check_if_exist(longurl)
if result == 0:
print("Info: The longurl {0} is not exist at serverside storage".format(longurl))
else:
print("Info: The longurl {0} is already exist at serverside storage".format(longurl))
return jsonify({'result':result,"longurl":longurl}),200
@app.route('/api/checkshorturl', methods=['POST'])
def check_short_url():
print("----come to function--- check_short_url() /api/check_short_url logic")
shorturl = request.json['shorturl']
result = check_shorturl_if_exist(shorturl)
if result == 0:
print("Info: The shorturl {0} is not exist at serverside storage".format(shorturl))
else:
print("Info: The shorturl {0} is already exist at serverside storage".format(shorturl))
return jsonify({'result':result,"shorturl":shorturl}),200
"""
1.收集長(zhǎng)鏈接生成短鏈接:
根據(jù)客戶端的post 請(qǐng)求,收集客戶端發(fā)送的shorturl以及l(fā)ongurl,把關(guān)聯(lián)關(guān)系插入到redis中
插入的時(shí)候,redis表中有兩個(gè)hash庫(kù),
"shorttolong" 庫(kù),結(jié)構(gòu)為 shorturl:{"longurl":longurl,"visittime",{},"createtime":string}
"longtoshort" 庫(kù),結(jié)構(gòu)為 longurl:shorturl
"""
@app.route('/api/shorturlcreate',methods=['POST'])
def shorturl_create():
print("----come to function---shorturl_create() /api/shorturlcreate logic")
shorturl = request.json['shorturl']
longurl = request.json['longurl']
insert_into_redis(shorturl, longurl)
print("info: insert into redis {0}:{1} pair success".format(shorturl,longurl))
return jsonify({"info":"insert into redis "+longurl+shorturl+" pair succuss"})
"""
2.收集短鏈接做相關(guān)跳轉(zhuǎn):
客戶端發(fā)出短鏈接請(qǐng)求,
2-1: 判斷短鏈接是否存在
2-2: 如果存在,則找到對(duì)應(yīng)的長(zhǎng)鏈接
2-3: 返回301 指令,并讓客戶端做跳轉(zhuǎn)
"""
@app.route('/api/shorturljump',methods=['POST'])
def shorturl_jump():
print("----come to function---shorturl_jump() /api/shorturljump logic")
shorturl = request.json['shorturl']
if check_shorturl_if_exist(shorturl) == 1:
# getlongurl mock
longurl=get_longurl(shorturl)
# 增加一個(gè)跳轉(zhuǎn)的時(shí)間,對(duì)他記錄。
# redis_update_jumptime(shorturl) mock
update_jumptime(shorturl)
# jumpto destination longurl,mock
print("info: jump to destination longurl {0} ".format(longurl))
#redirect_to_longurl(longurl)
return jsonify({"info": "jump to destionation","longurl":longurl})
else:
return jsonify({"info": "the site {0} is not exist".format(shorturl),"longurl":"notexist"})
if __name__ == '__main__':
app.run(host='0.0.0.0',port=8008,debug = True)
客戶端:
from flask import Flask,render_template,request,url_for,redirect
from datetime import date
import requests
import json
import time
def check_if_valid(longurl):
#檢查長(zhǎng)鏈接是否有效,這里mock一下
print("----come to function--- check_if_valid(longurl)")
try:
r = requests.get("https://"+longurl)
statuscode = r.status_code
if statuscode == 200 or statuscode == 301:
print("The site is reachable on internet")
result = 1
else:
result = 0
except:
result = 0
return result
def check_if_exist_url(longurl):
print("----come to function--- check_if_exist_url(longurl)")
#檢查長(zhǎng)鏈接是否在服務(wù)端存在,mock一下
print("Process: check if the longurl {0} is exist at serverside redis storage".format(longurl))
r = requests.post("http://127.0.0.1:8008/api/checkurl", json={"longurl": longurl})
textjson = r.json()
print("get the return info from the serverside {0}".format(longurl))
print(textjson)
print("get the type info of the serverside")
print(type(textjson))
print("Get the longurl ")
print(textjson["longurl"])
#print(dic2["longurl"])
result = textjson["result"]
return result
def post_shorturlcreate(shorturl,longurl):
#模擬postman,傳遞數(shù)據(jù)到服務(wù)端。
print("----come to function--- post_shorturlcreate(shorturl,longurl)")
print("Process: to deliver create link to serverside redis storage")
r = requests.post("http://127.0.0.1:8008/api/shorturlcreate",json={"shorturl":shorturl,"longurl":longurl})
print("get info from serverside \n"+ r.text)
return 1
def post_shorturljump(shorturl):
print("----come to function--- post_shorturljump(shorturl)")
print("Process: jump to shorturl")
r = requests.post("http://127.0.0.1:8008/api/shorturljump", json={"shorturl": shorturl})
print("get info from serverside \n" + r.text)
return r
def create_shorturl(longurl):
print("----come to function--- create_shorturl(longurl)")
print("Process: to create shorturl from longurl")
#返回shorturl
shorturl = "/"+longurl.split(".")[1]
print("Process:The short url is "+shorturl)
return shorturl
def check_shorturl_if_exist(shorturl):
print("----come to function--- check_shorturl_if_exist()")
print("Process: check if the shorturl {0} is exist at serverside redis storage".format(shorturl))
r = requests.post("http://127.0.0.1:8008/api/checkshorturl", json={"shorturl": shorturl})
textjson = r.json()
print("Print the info return from serverside,this is the info")
print(textjson)
print("Check the type of the info")
print(type(textjson))
print("Check the mapping(longurl) of the shorturl {0}".format(shorturl))
print(textjson["shorturl"])
# print(dic2["longurl"])
result = textjson["result"]
return result
app = Flask(__name__)
@app.route('/',methods=['GET','POST'])
def index():
if request.method == 'POST': #根據(jù)post 表單獲取的內(nèi)容做相關(guān)判斷
longurl = request.form['longurl']
shorturl = request.form['shorturl']
print("longurl is {0}, shorturl is {1}".format(longurl,shorturl))
if longurl is not None and shorturl == "empty": #當(dāng)longurl 非空
print("進(jìn)入第一個(gè)邏輯")
if check_if_valid(longurl) == 1 and check_if_exist_url(longurl) == 0: #當(dāng)longurl 可用,且longurl在服務(wù)端不存在
shorturl = create_shorturl(longurl)
post_shorturlcreate(shorturl, longurl)
notes = "the longurl {0} and shorturl {1} pair is created".format(longurl,shorturl)
return render_template('display.html', info=notes)
else: #否則條件沒達(dá)到,通知失敗
notes = "the longurl is not exist or it's already at serverside"
return render_template('display.html', info=notes)
if shorturl is not None and longurl == "empty": #當(dāng)shorturl 非空,執(zhí)行第二個(gè)邏輯
print("進(jìn)入第二個(gè)邏輯")
if check_shorturl_if_exist(shorturl) == 1:# 如果短url在服務(wù)端存在,則做跳轉(zhuǎn)等邏輯
r = post_shorturljump(shorturl)
print(r.json())
print(type(r.json()))
longurl = r.json()["longurl"]
print(longurl)
return redirect("https://" + longurl)
else:
notes = "the shorturl is not exist"
return render_template('display.html', info=notes)
if shorturl is not None and longurl == "statics": #當(dāng)shorturl 非空,且longurl為統(tǒng)計(jì),執(zhí)行第三個(gè)邏輯
print("進(jìn)入第三個(gè)邏輯")
visittime = []
if check_shorturl_if_exist(shorturl) == 1:# 如果短url在服務(wù)端存在,則收集它的訪問時(shí)間并存到字典
visittime =
else:
notes = "the shorturl is not exist"
return render_template('display.html', info=notes)
else:
return render_template('index5.html')
@app.route('/api/static',methods=['GET','POST'])
def get_static():
print("進(jìn)入第三個(gè)邏輯")
print("統(tǒng)計(jì)某個(gè)短鏈的訪問情況")
return render_template('display.html', info="The site info is displayed")
if __name__ == '__main__':
app.run(host='0.0.0.0',port=80,debug = True)
index5.html
<!DOCTYPE html>
<html lang="en">
<script type="text/javascript">
if(form.longurl.value ==''){
form.longurl.value == "empty"
}
if(form.shorturl.value ==''){
form.shorturl.value == "empty"
}
</script>
<head>
<meta charset="UTF-8">
<title>57-54</title>
</head>
<body>
<form method = "post">
<label for="longurl">提供想生成短鏈接的url</label>
<input type="text" name="longurl" required><br>
<input type="hidden" name="shorturl" value ="empty"><br>
<input type="submit" name="submit" value="記錄">
</form>
<form>
<label for="shorturl">提供想跳轉(zhuǎn)的url</label>
<input type="hidden" name="longurl" value="empty"><br>
<input type="text" name="shorturl" required><br>
<input type="submit" name="submit" value="跳轉(zhuǎn)">
</form>
</body>
</html>
display.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>57-53</title>
</head>
<body>
{{info}}
</body>
</html>
前端
鍵入www.qq.com
點(diǎn)擊記錄
實(shí)現(xiàn)了插入邏輯:
插入邏輯前端日志:
插入邏輯后端日志:
查看數(shù)據(jù)庫(kù):
跳轉(zhuǎn)前邏輯:
鍵入qq,點(diǎn)擊跳轉(zhuǎn)
跳轉(zhuǎn)后:
前端日志:
后端日志:
看訪問做了跳轉(zhuǎn)302,
update后,跳轉(zhuǎn)時(shí)間做了記錄
url腦圖
最常用的是直接請(qǐng)求,默認(rèn)是GET方法
curl <https://baidu.com>
添加header使用 -H, --header
curl -H "X-MY-HEADER: abc" <https://baidu.com>
如果想添加多個(gè)header,那么就寫多次
curl -H "X-MY-HEADER: abc" -H "X-MY-HEADER2: def" <https://baidu.com>
有些時(shí)候想要post或者put請(qǐng)求,可以使用 -X, --request <method> 來自設(shè)置
curl -X POST <https://baidu.com>
當(dāng)post的時(shí)候想要傳輸body參數(shù),可以使用 -d, --data <data> 來設(shè)置
curl -X POST -d "name=abc&gender=0" <https://example.com>
或者
curl -X POST -d name=bac -d gender=0 <https://example.com>
需要添加cookie來請(qǐng)求,可以使用 -b, --cookie 來設(shè)置
curl -b "token=abcdef;uid=123123" <https://example.com>
那如果想要把返回的cookie存儲(chǔ)起來呢,可以用 -c, --cookie-jar <file> 來設(shè)置存儲(chǔ)的位置
curl -c cookie.txt <https://www.baidu.com>
需要把請(qǐng)求的返回結(jié)果輸出到文件,以便查看分析,可以用 -o, --output <file> 來設(shè)置輸出到的文件
curl -o baidu.html <https://www.baidu.com>
示例如下圖,會(huì)打印出整體進(jìn)度和統(tǒng)計(jì)
curl被人熟知的是系統(tǒng)自帶的用來請(qǐng)求HTTP url的工具。但是,其不但可以處理http協(xié)議,還可以處理:FILE, FTP, FTPS, GOPHER, IMAP, IMAPS, LDAP, LDAPS, POP3, POP3S, RTMP, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET and TFTP等。。。這么多協(xié)議,怎樣,功能是不是很強(qiáng)大。
curl --mail-from "abc@def.com" --mail-rcpt "12345566@qq.com" --upload-file mail.txt --user "user_name:password" --url "smtp://mail.qq.com"
curl -T "img[1-1000].png" <ftp://ftp.example.com/upload/>
或者
curl --upload-file "{file1,file2}" <http://www.example.com>
最簡(jiǎn)單的使用方式是:curl <https://baidu.com> ,但是偶爾會(huì)有想同時(shí)請(qǐng)求多個(gè)url,能不能辦的到呢,當(dāng)然可以
curl https://{baidu,cnblogs}.com
這樣的話就會(huì)順序請(qǐng)求 https://baidu.com、https://cnblogs.com 這兩個(gè)網(wǎng)站。(PS: 終端里顯示{ 或}之前有\(zhòng),是終端做的轉(zhuǎn)義功能,請(qǐng)忽略。)
又有說請(qǐng)求的url不一定都是.com結(jié)尾呢,能不能辦呢,那必須可以
curl https://{baidu.com,csdn.net}
又有人較真說,我請(qǐng)求的多個(gè)url協(xié)議都是不同的,比如:curl {<http://baidu.com>, <https://csdn.net>} , 能不能這么請(qǐng)求呢,那不好意思,這樣不行,會(huì)解析錯(cuò)誤。
這種用法多用于某個(gè)站點(diǎn)多種path或query的情況,比如
可以使用 -x,--proxy [protocol://]host[:port] 參數(shù) 代理來請(qǐng)求目標(biāo)網(wǎng)站
curl --proxy <http://127.0.0.1:1087> <https://baidu.com>
使用http的代理是可以來請(qǐng)求https目標(biāo)網(wǎng)站的,其中原理是使用了http的proxy tunnel功能,這個(gè)在后續(xù)文章中會(huì)做詳細(xì)介紹。
有些時(shí)候想要知道詳細(xì)的請(qǐng)求情況,比如怎么建立連接的,請(qǐng)求過程是如何的,那么可以這么來用,使用 -v ,--verbose
curl -v <https://baidu.com>
有了上面的詳細(xì)請(qǐng)求可能還不太滿足一些需求,比如想要知道花費(fèi)建立連接時(shí)間、傳輸時(shí)間、相應(yīng)時(shí)間等詳細(xì)的性能信息,這個(gè)對(duì)于最終網(wǎng)絡(luò)問題很有幫助,那么怎么辦呢。
那就要拿出一個(gè)厲害的參數(shù):-w, —write-out
比如下面的例子可以輸出:發(fā)起鏈接時(shí)間,開始傳輸時(shí)間以及總花費(fèi)時(shí)間。
curl -w 'time_connect %{time_connect}s\ntime_starttransfer %{time_starttransfer}s\ntime_total %{time_total}s\n' <https://baidu.com>
可以來一個(gè)更詳細(xì)的追蹤
curl -w 'http_code: %{http_code}\ncontent_type: %{content_type}\ntime_namelookup: %{time_namelookup}\ntime_connect: %{time_connect}\ntime_appconnect: %{time_appconnect}\ntime_redirect: %{time_redirect}\ntime_pretransfer: %{time_pretransfer}\ntime_starttransfer: %{time_starttransfer}\nspeed_download: %{speed_download}\nspeed_upload: %{speed_upload}\nsize_download: %{size_download}\nsize_upload: %{size_upload}\n---------\n time_total: %{time_total}\n' <https://baidu.com>
結(jié)果如下圖
-w 可以使用的變量比較多,常用的如下表所示:
可以設(shè)置失敗請(qǐng)求重試次數(shù),以及最大重試次數(shù)、超時(shí)時(shí)間等。
例如,設(shè)置重復(fù)次數(shù)請(qǐng)求一個(gè)不存在的url
curl --retry 3 --retry-delay 1 --retry-max-time 10 <https://notexisturl.com>
例如,設(shè)置超時(shí)時(shí)間來請(qǐng)求
curl -m 1 <https://baidu.com>
pring Security 系列繼續(xù)。
前面的視頻+文章,松哥和大家簡(jiǎn)單聊了 Spring Security 的基本用法,并且我們一起自定義了一個(gè)登錄頁面,讓登錄看起來更炫一些!
今天我們來繼續(xù)深入這個(gè)表單配置,挖掘一下這里邊常見的其他配置。學(xué)習(xí)本文,強(qiáng)烈建議大家看一下前置知識(shí)(松哥手把手帶你入門 Spring Security,別再問密碼怎么解密了),學(xué)習(xí)效果更佳。
很多初學(xué)者分不清登錄接口和登錄頁面,這個(gè)我也很郁悶。我還是在這里稍微說一下。
登錄頁面就是你看到的瀏覽器展示出來的頁面,像下面這個(gè):
登錄接口則是提交登錄數(shù)據(jù)的地方,就是登錄頁面里邊的 form 表單的 action 屬性對(duì)應(yīng)的值。
在 Spring Security 中,如果我們不做任何配置,默認(rèn)的登錄頁面和登錄接口的地址都是 /login,也就是說,默認(rèn)會(huì)存在如下兩個(gè)請(qǐng)求:
如果是 GET 請(qǐng)求表示你想訪問登錄頁面,如果是 POST 請(qǐng)求,表示你想提交登錄數(shù)據(jù)。
在上篇文章中,我們?cè)?SecurityConfig 中自定定義了登錄頁面地址,如下:
.and()
.formLogin()
.loginPage("/login.html")
.permitAll()
.and()
當(dāng)我們配置了 loginPage 為 /login.html 之后,這個(gè)配置從字面上理解,就是設(shè)置登錄頁面的地址為 /login.html。
實(shí)際上它還有一個(gè)隱藏的操作,就是登錄接口地址也設(shè)置成 /login.html 了。換句話說,新的登錄頁面和登錄接口地址都是 /login.html,現(xiàn)在存在如下兩個(gè)請(qǐng)求:
前面的 GET 請(qǐng)求用來獲取登錄頁面,后面的 POST 請(qǐng)求用來提交登錄數(shù)據(jù)。
有的小伙伴會(huì)感到奇怪?為什么登錄頁面和登錄接口不能分開配置呢?
其實(shí)是可以分開配置的!
在 SecurityConfig 中,我們可以通過 loginProcessingUrl 方法來指定登錄接口地址,如下:
.and()
.formLogin()
.loginPage("/login.html")
.loginProcessingUrl("/doLogin")
.permitAll()
.and()
這樣配置之后,登錄頁面地址和登錄接口地址就分開了,各是各的。
此時(shí)我們還需要修改登錄頁面里邊的 action 屬性,改為 /doLogin,如下:
<form action="/doLogin" method="post">
<!--省略-->
</form>
此時(shí),啟動(dòng)項(xiàng)目重新進(jìn)行登錄,我們發(fā)現(xiàn)依然可以登錄成功。
那么為什么默認(rèn)情況下兩個(gè)配置地址是一樣的呢?
我們知道,form 表單的相關(guān)配置在 FormLoginConfigurer 中,該類繼承自 AbstractAuthenticationFilterConfigurer ,所以當(dāng) FormLoginConfigurer 初始化的時(shí)候,AbstractAuthenticationFilterConfigurer 也會(huì)初始化,在 AbstractAuthenticationFilterConfigurer 的構(gòu)造方法中,我們可以看到:
protected AbstractAuthenticationFilterConfigurer() {
setLoginPage("/login");
}
這就是配置默認(rèn)的 loginPage 為 /login。
另一方面,F(xiàn)ormLoginConfigurer 的初始化方法 init 方法中也調(diào)用了父類的 init 方法:
public void init(H http) throws Exception {
super.init(http);
initDefaultLoginFilter(http);
}
而在父類的 init 方法中,又調(diào)用了 updateAuthenticationDefaults,我們來看下這個(gè)方法:
protected final void updateAuthenticationDefaults() {
if (loginProcessingUrl == null) {
loginProcessingUrl(loginPage);
}
//省略
}
從這個(gè)方法的邏輯中我們就可以看到,如果用戶沒有給 loginProcessingUrl 設(shè)置值的話,默認(rèn)就使用 loginPage 作為 loginProcessingUrl。
而如果用戶配置了 loginPage,在配置完 loginPage 之后,updateAuthenticationDefaults 方法還是會(huì)被調(diào)用,此時(shí)如果沒有配置 loginProcessingUrl,則使用新配置的 loginPage 作為 loginProcessingUrl。
好了,看到這里,相信小伙伴就明白了為什么一開始的登錄接口和登錄頁面地址一樣了。
說完登錄接口,我們?cè)賮碚f登錄參數(shù)。
在上篇文章中,我們的登錄表單中的參數(shù)是 username 和 password,注意,默認(rèn)情況下,這個(gè)不能變:
<form action="/login.html" method="post">
<input type="text" name="username" id="name">
<input type="password" name="password" id="pass">
<button type="submit">
<span>登錄</span>
</button>
</form>
那么為什么是這樣呢?
還是回到 FormLoginConfigurer 類中,在它的構(gòu)造方法中,我們可以看到有兩個(gè)配置用戶名密碼的方法:
public FormLoginConfigurer() {
super(new UsernamePasswordAuthenticationFilter(), null);
usernameParameter("username");
passwordParameter("password");
}
在這里,首先 super 調(diào)用了父類的構(gòu)造方法,傳入了 UsernamePasswordAuthenticationFilter 實(shí)例,該實(shí)例將被賦值給父類的 authFilter 屬性。
接下來 usernameParameter 方法如下:
public FormLoginConfigurer<H> usernameParameter(String usernameParameter) {
getAuthenticationFilter().setUsernameParameter(usernameParameter);
return this;
}
getAuthenticationFilter 實(shí)際上是父類的方法,在這個(gè)方法中返回了 authFilter 屬性,也就是一開始設(shè)置的 UsernamePasswordAuthenticationFilter 實(shí)例,然后調(diào)用該實(shí)例的 setUsernameParameter 方法去設(shè)置登錄用戶名的參數(shù):
public void setUsernameParameter(String usernameParameter) {
this.usernameParameter = usernameParameter;
}
這里的設(shè)置有什么用呢?當(dāng)?shù)卿浾?qǐng)求從瀏覽器來到服務(wù)端之后,我們要從請(qǐng)求的 HttpServletRequest 中取出來用戶的登錄用戶名和登錄密碼,怎么取呢?還是在 UsernamePasswordAuthenticationFilter 類中,有如下兩個(gè)方法:
protected String obtainPassword(HttpServletRequest request) {
return request.getParameter(passwordParameter);
}
protected String obtainUsername(HttpServletRequest request) {
return request.getParameter(usernameParameter);
}
可以看到,這個(gè)時(shí)候,就用到默認(rèn)配置的 username 和 password 了。
當(dāng)然,這兩個(gè)參數(shù)我們也可以自己配置,自己配置方式如下:
.and()
.formLogin()
.loginPage("/login.html")
.loginProcessingUrl("/doLogin")
.usernameParameter("name")
.passwordParameter("passwd")
.permitAll()
.and()
配置完成后,也要修改一下前端頁面:
<form action="/doLogin" method="post">
<div class="input">
<label for="name">用戶名</label>
<input type="text" name="name" id="name">
<span class="spin"></span>
</div>
<div class="input">
<label for="pass">密碼</label>
<input type="password" name="passwd" id="pass">
<span class="spin"></span>
</div>
<div class="button login">
<button type="submit">
<span>登錄</span>
<i class="fa fa-check"></i>
</button>
</div>
</form>
注意修改 input 的 name 屬性值和服務(wù)端的對(duì)應(yīng)。
配置完成后,重啟進(jìn)行登錄測(cè)試。
在登錄成功之后,我們就要分情況處理了,大體上來說,無非就是分為兩種情況:
兩種情況的處理方式不一樣。本文我們先來卡第二種前后端不分的登錄,前后端分離的登錄回調(diào)我在下篇文章中再來和大家細(xì)說。
在 Spring Security 中,和登錄成功重定向 URL 相關(guān)的方法有兩個(gè):
這兩個(gè)咋看沒什么區(qū)別,實(shí)際上內(nèi)藏乾坤。
首先我們?cè)谂渲玫臅r(shí)候,defaultSuccessUrl 和 successForwardUrl 只需要配置一個(gè)即可,具體配置哪個(gè),則要看你的需求,兩個(gè)的區(qū)別如下:
相關(guān)配置如下:
.and()
.formLogin()
.loginPage("/login.html")
.loginProcessingUrl("/doLogin")
.usernameParameter("name")
.passwordParameter("passwd")
.defaultSuccessUrl("/index")
.successForwardUrl("/index")
.permitAll()
.and()
「注意:實(shí)際操作中,defaultSuccessUrl 和 successForwardUrl 只需要配置一個(gè)即可。」
與登錄成功相似,登錄失敗也是有兩個(gè)方法:
「這兩個(gè)方法在設(shè)置的時(shí)候也是設(shè)置一個(gè)即可」。failureForwardUrl 是登錄失敗之后會(huì)發(fā)生服務(wù)端跳轉(zhuǎn),failureUrl 則在登錄失敗之后,會(huì)發(fā)生重定向。
注銷登錄的默認(rèn)接口是 /logout,我們也可以配置。
.and()
.logout()
.logoutUrl("/logout")
.logoutRequestMatcher(new AntPathRequestMatcher("/logout","POST"))
.logoutSuccessUrl("/index")
.deleteCookies()
.clearAuthentication(true)
.invalidateHttpSession(true)
.permitAll()
.and()
注銷登錄的配置我來說一下:
好了,今天就先說這么多,這塊還剩一些前后端分離交互的,松哥在下篇文章再來和大家細(xì)說。
「如果感覺有收獲,記得點(diǎn)一下右下角在看哦」
*請(qǐng)認(rèn)真填寫需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。