用户认证与授权(登录功能)
截至目前,項(xiàng)目已經(jīng)完成了在線學(xué)習(xí)功能,用戶通過在線學(xué)習(xí)頁面點(diǎn)播視頻進(jìn)行學(xué)習(xí)。如何去記錄學(xué)生的學(xué)習(xí)過程呢?要想掌握學(xué)生的學(xué)習(xí)情況就需要知道用戶的身份信息,記錄哪個(gè)用戶在什么時(shí)間學(xué)習(xí)什么課程;如果用戶要購買課程也需要知道用戶的身份信息。所以,去管理學(xué)生的學(xué)習(xí)過程最基本的要實(shí)現(xiàn)用戶的身份認(rèn)證。
什么是用戶身份認(rèn)證?
用戶身份認(rèn)證即用戶去訪問系統(tǒng)資源時(shí)系統(tǒng)要求驗(yàn)證用戶的身份信息,身份合法方可繼續(xù)訪問。常見的用戶身份認(rèn)證表現(xiàn)形式有:用戶名密碼登錄,指紋打卡等方式。
什么是用戶授權(quán)?
用戶認(rèn)證通過后去訪問系統(tǒng)的資源,系統(tǒng)會(huì)判斷用戶是否擁有訪問資源的權(quán)限,只允許訪問有權(quán)限的系統(tǒng)資源,沒有權(quán)限的資源將無法訪問,這個(gè)過程叫用戶授權(quán)。
本項(xiàng)目包括多個(gè)子項(xiàng)目(微服務(wù)),如:學(xué)習(xí)系統(tǒng),教學(xué)管理中心、系統(tǒng)管理中心等,為了提高用戶體驗(yàn)性需要實(shí)現(xiàn)用戶只認(rèn)證一次便可以在多個(gè)擁有訪問權(quán)限的系統(tǒng)中訪問,這個(gè)功能叫做單點(diǎn)登錄。
本項(xiàng)目采用 Spring security + Oauth2完成用戶認(rèn)證及用戶授權(quán)。流程如下:
1、用戶請(qǐng)求認(rèn)證服務(wù)完成認(rèn)證。
2、認(rèn)證服務(wù)下發(fā)用戶身份令牌,擁有身份令牌表示身份合法。
3、用戶攜帶令牌請(qǐng)求資源服務(wù),請(qǐng)求資源服務(wù)必先經(jīng)過網(wǎng)關(guān)。
4、網(wǎng)關(guān)校驗(yàn)用戶身份令牌的合法,不合法表示用戶沒有登錄,如果合法則放行繼續(xù)訪問。
5、資源服務(wù)獲取令牌,根據(jù)令牌完成授權(quán)。
6、資源服務(wù)完成授權(quán)則響應(yīng)資源信息。
一、 Spring security Oauth2認(rèn)證解決方案
搭建認(rèn)證服務(wù)器
創(chuàng)建xc-service-ucenter-auth工程,該工程是基于Spring Security Oauth2的一個(gè)二次封裝的工程。
創(chuàng)建用戶數(shù)據(jù)庫
以“oauth_”開頭的表都是spring Security 自帶的表。
本項(xiàng)目中spring Security 主要使用oauth_client_details表:
client_id:客戶端id
resource_ids:資源id(暫時(shí)不用)
client_secret:客戶端密碼
scope:范圍
access_token_validity:訪問token的有效期(秒)
refresh_token_validity:刷新token的有效期(秒)
authorized_grant_type:授權(quán)類型,authorization_code,password,refresh_token,client_credentials
Oauth2授權(quán)模式
Oauth2有以下授權(quán)模式: 授權(quán)碼模式(Authorization Code) 隱式授權(quán)模式(Implicit) 密碼模式(Resource Owner Password Credentials) 客戶端模式(Client Credentials) 其中授權(quán)碼模式和密碼模式應(yīng)用較多。
密碼模式與授權(quán)碼模式的區(qū)別是申請(qǐng)令牌不再使用授權(quán)碼,而是直接通過用戶名和密碼即可申請(qǐng)令牌。
Oauth2授權(quán)碼模式和密碼模式的使用教程見講義。
本項(xiàng)目使用密碼模式。
二、資源服務(wù)授權(quán)
資源服務(wù)授權(quán)流程
1、客戶端請(qǐng)求認(rèn)證服務(wù)申請(qǐng)令牌
2、認(rèn)證服務(wù)生成令牌
認(rèn)證服務(wù)采用非對(duì)稱加密算法,使用私鑰生成令牌。
3、客戶端攜帶令牌訪問資源服務(wù)
客戶端在Http header 中添加: Authorization:Bearer 令牌。
4、資源服務(wù)請(qǐng)求認(rèn)證服務(wù)校驗(yàn)令牌的有效性
資源服務(wù)接收到令牌,使用公鑰校驗(yàn)令牌的合法性。
5、令牌有效,資源服務(wù)向客戶端響應(yīng)資源信息
資源服務(wù)授權(quán)配置
基本上所有微服務(wù)都是資源服務(wù),這里我們?cè)谡n程管理服務(wù)上配置授權(quán)控制,當(dāng)配置了授權(quán)控制后如要訪問課程信息則必須提供令牌。
1、配置公鑰
認(rèn)證服務(wù)生成令牌采用非對(duì)稱加密算法,認(rèn)證服務(wù)采用私鑰加密生成令牌,對(duì)外向資源服務(wù)提供公鑰,資源服務(wù)使 用公鑰來校驗(yàn)令牌的合法性。
將公鑰拷貝到 publickey.txt文件中,將此文件拷貝到資源服務(wù)工程的classpath下:
2、添加依賴
3、在config包下創(chuàng)建ResourceServerConfig類:
@Configuration @EnableResourceServer @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)//激活方法上的 PreAuthorize注解 public class ResourceServerConfig extends ResourceServerConfigurerAdapter { //公鑰 private static final String PUBLIC_KEY = "publickey.txt";//定義JwtTokenStore,使用jwt令牌 @Bean public TokenStore tokenStore(JwtAccessTokenConverter jwtAccessTokenConverter) { return new JwtTokenStore(jwtAccessTokenConverter); }//定義JJwtAccessTokenConverter,使用jwt令牌 @Bean public JwtAccessTokenConverter jwtAccessTokenConverter() { JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); converter.setVerifierKey(getPubKey()); return converter; }/*** 獲取非對(duì)稱加密公鑰 Key * @return 公鑰 Key */ private String getPubKey() { Resource resource = new ClassPathResource(PUBLIC_KEY); try {InputStreamReader inputStreamReader = new InputStreamReader(resource.getInputStream()); BufferedReader br = new BufferedReader(inputStreamReader); return br.lines().collect(Collectors.joining("\n")); } catch (IOException ioe) { return null; } }//Http安全配置,對(duì)每個(gè)到達(dá)系統(tǒng)的http請(qǐng)求鏈接進(jìn)行校驗(yàn) @Override public void configure(HttpSecurity http) throws Exception { //所有請(qǐng)求必須認(rèn)證通過 http.authorizeRequests().anyRequest().authenticated(); } }JWT介紹
在介紹JWT之前先看一下傳統(tǒng)校驗(yàn)令牌的方法,如下圖:
問題:
傳統(tǒng)授權(quán)方法的問題是用戶每次請(qǐng)求資源服務(wù),資源服務(wù)都需要攜帶令牌訪問認(rèn)證服務(wù)去校驗(yàn)令牌的合法性,并根據(jù)令牌獲取用戶的相關(guān)信息,性能低下。
解決:
使用JWT的思路是,用戶認(rèn)證通過會(huì)得到一個(gè)JWT令牌,JWT令牌中已經(jīng)包括了用戶相關(guān)的信息,客戶端只需要攜帶JWT訪問資源服務(wù),資源服務(wù)根據(jù)事先約定的算法自行完成令牌校驗(yàn)(使用公鑰),無需每次都請(qǐng)求認(rèn)證服務(wù)完成授權(quán)。
JWT令牌授權(quán)過程如下圖:
JWT令牌結(jié)構(gòu)
JWT令牌由三部分組成,每部分中間使用點(diǎn)(.)分隔,比如:xxxxx.yyyyy.zzzzz。
Header 頭部包括令牌的類型(即JWT)及使用的哈希算法(如HMAC SHA256或RSA),
例子如下:
將上邊的內(nèi)容使用Base64Url編碼,得到一個(gè)字符串就是JWT令牌的第一部分。
Payload
第二部分是負(fù)載,內(nèi)容也是一個(gè)json對(duì)象,它是存放有效信息的地方,它可以存放jwt提供的現(xiàn)成字段,比 如:iss(簽發(fā)者),exp(過期時(shí)間戳), sub(面向的用戶)等,也可自定義字段。 此部分不建議存放敏感信息,因?yàn)榇瞬糠挚梢越獯a還原原始內(nèi)容。 最后將第二部分負(fù)載使用Base64Url編碼,得到一個(gè)字符串就是JWT令牌的第二部分。
Signature
第三部分是簽名,此部分用于防止jwt內(nèi)容被篡改。 這個(gè)部分使用base64url將前兩部分進(jìn)行編碼,編碼后使用點(diǎn)(.)連接組成字符串,最后使用header中聲明 簽名算法進(jìn)行簽名。
一個(gè)例子:
base64UrlEncode(header):jwt令牌的第一部分。 base64UrlEncode(payload):jwt令牌的第二部分。 secret:簽名所使用的密鑰。
Spring Security 提供JwtHelper來實(shí)現(xiàn)創(chuàng)建JWT令牌,校驗(yàn)JWT令牌等操作。
三、認(rèn)證接口開發(fā)
執(zhí)行流程:
1、用戶登錄,請(qǐng)求認(rèn)證服務(wù)
2、認(rèn)證服務(wù)認(rèn)證通過,生成jwt令牌,將jwt令牌及相關(guān)信息寫入Redis,并且將身份令牌寫入cookie
3、用戶訪問資源頁面,帶著cookie到網(wǎng)關(guān)
4、網(wǎng)關(guān)從cookie獲取token,并查詢Redis校驗(yàn)token,如果token不存在則拒絕訪問,否則放行
5、用戶退出,請(qǐng)求認(rèn)證服務(wù),清除redis中的token,并且刪除cookie中的token
使用redis存儲(chǔ)用戶的身份令牌有以下作用: 1、實(shí)現(xiàn)用戶退出注銷功能,服務(wù)端清除令牌后,即使客戶端請(qǐng)求攜帶token也是無效的。 2、由于jwt令牌過長,不宜存儲(chǔ)在cookie中,所以將jwt令牌存儲(chǔ)在redis,由客戶端請(qǐng)求服務(wù)端獲取并在客戶端存儲(chǔ)。
下一篇繼續(xù)。
總結(jié)
以上是生活随笔為你收集整理的用户认证与授权(登录功能)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 快速学习的一些方法
- 下一篇: 三角兽散招实习面试题