Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
前的一篇文章介紹了首頁如何生成驗(yàn)證碼,這篇筆記主要介紹一下登錄請求的發(fā)起與后臺的驗(yàn)證。
首先還是打開登陸驗(yàn)證的頁面,輸入用戶名和密碼通過瀏覽器開發(fā)者工具進(jìn)行調(diào)試,很容易就能看到登錄發(fā)起的請求,如下圖所示:
我們可以看到請求的url為:
http://localhost/dev-api/login
我們可以去后端工程中去尋找/login相關(guān)的控制層的代碼。控制層的代碼也在ruoyi-admin工程下面,名字是SysLoginController,其中的部分源碼如下所示:
/**
* 登錄方法
*
* @param loginBody 登錄信息
* @return 結(jié)果
*/
@PostMapping("/login")
public AjaxResult login(@RequestBody LoginBody loginBody)
{
AjaxResult ajax=AjaxResult.success();
// 生成令牌
String token=loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
loginBody.getUuid());
ajax.put(Constants.TOKEN, token);
return ajax;
}
這里分析一下后端介紹到請求之后的邏輯,本文省略掉一些前端部分關(guān)于登錄驗(yàn)證方面的校驗(yàn)。首先后端接收到登錄的請求,請求體被封裝成了一個對象,控制層中調(diào)用service層的方法進(jìn)行進(jìn)一步的驗(yàn)證。
驗(yàn)證的核心代碼在控制層對應(yīng)的服務(wù)層中,首先第一步是判斷驗(yàn)證碼,如果開啟了驗(yàn)證碼,則會調(diào)用一個封裝好的方法,從 redis中讀取答案,其中uuid的用處是用于從 redis中找到本次登錄請求那個驗(yàn)證碼所對應(yīng)的正確答案。驗(yàn)證碼判斷具體的邏輯位于SysLoginService.java中的源碼里面的validateCaptcha這個方法。
public String login(String username, String password, String code, String uuid)
{
boolean captchaOnOff=configService.selectCaptchaOnOff();
// 驗(yàn)證碼開關(guān)
if (captchaOnOff)
{
validateCaptcha(username, code, uuid);
}
// 用戶驗(yàn)證
Authentication authentication=null;
try
{
// 該方法會去調(diào)用UserDetailsServiceImpl.loadUserByUsername
authentication=authenticationManager
.authenticate(new UsernamePasswordAuthenticationToken(username, password));
}
catch (Exception e)
{
if (e instanceof BadCredentialsException)
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
throw new UserPasswordNotMatchException();
}
else
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
throw new ServiceException(e.getMessage());
}
}
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
LoginUser loginUser=(LoginUser) authentication.getPrincipal();
recordLoginInfo(loginUser.getUserId());
// 生成token
return tokenService.createToken(loginUser);
}
判斷完驗(yàn)證碼之后,如果驗(yàn)證碼正確,下一步就是進(jìn)行用戶名和密碼的驗(yàn)證。這部分驗(yàn)證使用了SpringSecurity,這里是判斷了用戶名和密碼。
這個框架中驗(yàn)證和授權(quán)都是使用了SpringSecurity。我們首先要關(guān)注這么一個配置類SecurityConfig.java,這個類繼承了SpringSecurity的一個WebSecurityConfigurerAdapter,并且重寫了其中的幾個方法,來進(jìn)行驗(yàn)證方面的配置,很多配置都是固定的。這里的身份驗(yàn)證用了jwt,所以這里禁用了SpringSecurity自帶的csrf認(rèn)證機(jī)制,并且通過過濾規(guī)則過濾掉了一些頁面。這個項目是前后端分離的項目,這里也沒有專門配置登錄的頁面。
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception
{
httpSecurity
// CSRF禁用,因?yàn)椴皇褂胹ession
.csrf().disable()
// 認(rèn)證失敗處理類
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
// 基于token,所以不需要session
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
// 過濾請求
.authorizeRequests()
// 對于登錄login 注冊register 驗(yàn)證碼captchaImage 允許匿名訪問
.antMatchers("/login", "/register", "/captchaImage").anonymous()
.antMatchers(
HttpMethod.GET,
"/",
"/*.html",
"/**/*.html",
"/**/*.css",
"/**/*.js",
"/profile/**"
).permitAll()
.antMatchers("/swagger-ui.html").anonymous()
.antMatchers("/swagger-resources/**").anonymous()
.antMatchers("/webjars/**").anonymous()
.antMatchers("/*/api-docs").anonymous()
.antMatchers("/druid/**").anonymous()
// 除上面外的所有請求全部需要鑒權(quán)認(rèn)證
.anyRequest().authenticated()
.and()
.headers().frameOptions().disable();
httpSecurity.logout().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler);
// 添加JWT filter
httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
// 添加CORS filter
httpSecurity.addFilterBefore(corsFilter, JwtAuthenticationTokenFilter.class);
httpSecurity.addFilterBefore(corsFilter, LogoutFilter.class);
}
這里調(diào)用自定義用戶認(rèn)證邏輯,并且對加密過的密碼做一個解密。
//認(rèn)證
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
{
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
}
另外一個需要關(guān)注的點(diǎn),是自定義的用戶認(rèn)證邏輯,框架中作者實(shí)現(xiàn)了UserDetailsService這個接口,具體的代碼在UserDetailsServiceImpl.java中,會通過查詢數(shù)據(jù)庫判斷用戶是否存在。
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
{
SysUser user=userService.selectUserByUserName(username);
if (StringUtils.isNull(user))
{
log.info("登錄用戶:{} 不存在.", username);
throw new ServiceException("登錄用戶:" + username + " 不存在");
}
else if (UserStatus.DELETED.getCode().equals(user.getDelFlag()))
{
log.info("登錄用戶:{} 已被刪除.", username);
throw new ServiceException("對不起,您的賬號:" + username + " 已被刪除");
}
else if (UserStatus.DISABLE.getCode().equals(user.getStatus()))
{
log.info("登錄用戶:{} 已被停用.", username);
throw new ServiceException("對不起,您的賬號:" + username + " 已停用");
}
return createLoginUser(user);
}
雖然在登錄驗(yàn)證密碼的service層中,在判斷完驗(yàn)證碼之后,進(jìn)行用戶名和密碼的比對,在其service層中僅僅只是調(diào)用了springSecurity一個攔截器方法,但是對于整個項目本身我們還是要進(jìn)行很多的配置才能正常的使用。
try
{
// 該方法會去調(diào)用UserDetailsServiceImpl.loadUserByUsername
authentication=authenticationManager
.authenticate(new UsernamePasswordAuthenticationToken(username, password));
}
整個框架對于驗(yàn)證的判斷是首先判斷驗(yàn)證碼,然后是調(diào)用SpringSecurity框架進(jìn)行用戶名和密碼的判斷,并且還會對于用戶名做個自定義的校驗(yàn)。
題中的 “傳統(tǒng)Web應(yīng)用” 這一說法并沒有什么官方定義,只是為了與“現(xiàn)代化Web應(yīng)用”做比較而自擬的一個概念。所謂“現(xiàn)代化Web應(yīng)用”指的是那些基于分布式架構(gòu)思想設(shè)計的,面向多個端提供穩(wěn)定可靠的高可用服務(wù),并且在需要時能夠橫向擴(kuò)展的Web應(yīng)用。相對而言,傳統(tǒng)Web應(yīng)用則主要是直接面向PC用戶的Web應(yīng)用程序,采用單體架構(gòu)較多,也可能在內(nèi)部采用SOA的分布式運(yùn)算技術(shù)。
一直以來,傳統(tǒng)Web應(yīng)用為構(gòu)成互聯(lián)網(wǎng)發(fā)揮了重要作用。因此傳統(tǒng)Web應(yīng)用中的身份驗(yàn)證技術(shù)經(jīng)過幾代的發(fā)展,已經(jīng)解決了不少實(shí)際問題,并最終沉淀了一些實(shí)踐模式。
在講述多種身份鑒權(quán)技術(shù)之前,要強(qiáng)調(diào)一點(diǎn):在構(gòu)建互聯(lián)網(wǎng)Web應(yīng)用過程中,無論使用哪種技術(shù),在傳輸用戶名和密碼時,請一定要采用安全連接模式。因?yàn)闊o論采用何種鑒權(quán)模型,都無法保護(hù)用戶憑據(jù)在傳輸過程中不被竊取。
Basic和Digest鑒權(quán)
基于HTTP的Web應(yīng)用離不開HTTP本身的安全特性中關(guān)于身份鑒權(quán)的部分。雖然HTTP標(biāo)準(zhǔn)定義了好幾種鑒權(quán)方式,但真正供Web應(yīng)用開發(fā)者選擇的并不多,這里簡要回顧一下曾經(jīng)被廣泛運(yùn)用過的Basic 和 Digest鑒權(quán)。
不知道讀者是否熟悉一種最直接向服務(wù)器提供身份的方式,即在URL中直接寫上用戶名和密碼:
http://user:passwd@www.server.com/index.html
這就是Basic鑒權(quán)的一種形式。
Basic和Digest是通過在HTTP請求中直接包含用戶名和密碼,或者它們的哈希值來向服務(wù)器傳輸用戶憑據(jù)的方法。Basic鑒權(quán)直接在每個請求的頭部或URL中包含明文的用戶名或密碼,或者經(jīng)過Base64編碼過的用戶名或密碼;而Digest則會使用服務(wù)器返回的隨機(jī)值,對用戶名和密碼拼裝后,使用多次MD5哈希處理后再向服務(wù)器傳輸。服務(wù)器在處理每個請求之前,讀取收到的憑據(jù),并鑒定用戶的身份。
Basic和Digest鑒權(quán)有一系列的缺陷。它們需要在每個請求中提供憑據(jù),因此提供“記住登錄狀態(tài)”功能的網(wǎng)站中,不得不將用戶憑據(jù)緩存在瀏覽器中,增加了用戶的安全風(fēng)險。Basic鑒權(quán)基本不對用戶名和密碼等敏感信息進(jìn)行預(yù)處理,所以只適合于較安全的安全環(huán)境,如通過HTTPS安全連接傳輸,或者局域網(wǎng)。
看起來更安全的Digest在非安全連接傳輸過程中,也無法抵御中間人通過篡改響應(yīng)來要求客戶端降級為Basic鑒權(quán)的攻擊。Digest鑒權(quán)還有一個缺陷:由于在服務(wù)器端需要核對收到的、由客戶端經(jīng)過多次MD5哈希值的合法性,需要使用原始密碼做相同的運(yùn)算,這讓服務(wù)器無法在存儲密碼之前對其進(jìn)行不可逆的加密。Basic 和Digest鑒權(quán)的缺陷決定了它們不可能在互聯(lián)網(wǎng)Web應(yīng)用中被大量采用。
簡單實(shí)用的登錄技術(shù)
對于互聯(lián)網(wǎng)Web應(yīng)用來說,不采用Basic或Digest鑒權(quán)的理由主要有兩個:
1. 不能接受在每個請求中發(fā)送用戶名和密碼憑據(jù)
2. 需要在服務(wù)器端對密碼進(jìn)行不可逆的加密
因此,互聯(lián)網(wǎng)Web應(yīng)用開發(fā)已經(jīng)形成了一個基本的實(shí)踐模式,能夠在服務(wù)端對密碼強(qiáng)加密之后存儲,并且盡量減少鑒權(quán)過程中對憑據(jù)的傳輸。其過程如下圖所示:
這一過程的原理很簡單,專門發(fā)送一個鑒權(quán)請求,只在這個請求頭中包含原始用戶名和密碼憑據(jù),經(jīng)服務(wù)器驗(yàn)證合法之后,由服務(wù)器發(fā)給一個會話標(biāo)識(Session ID),客戶端將會話標(biāo)識存儲在 Cookie 中,服務(wù)器記錄會話標(biāo)識與經(jīng)過驗(yàn)證的用戶的對應(yīng)關(guān)系;后續(xù)客戶端使用會話標(biāo)識、而不是原始憑據(jù)去與服務(wù)器交互,服務(wù)器讀取到會話標(biāo)識后從自身的會話存儲中讀取已在第一個鑒權(quán)請求中驗(yàn)證過的用戶身份。為了保護(hù)用戶的原始憑據(jù)在傳輸中的安全,只需要為第一個鑒權(quán)請求構(gòu)建安全連接支持。
服務(wù)端的代碼包含首次鑒權(quán)和后續(xù)檢查并授權(quán)訪問的過程:
IUser _user_;
if( validateLogin( nameFromReq, pwdFromReq, out _user _)){
Session["CurrentUser"]=_user_;
}
(首次鑒權(quán))
IUser _user_=Session["CurrentUser"] as IUser;
if( _user_==null ){
Response.Redirect( "/login?return_uri=" +
Request.Url.ToString() );
return;
}
(后續(xù)檢查并拒絕未識別的用戶)
類似這樣的技術(shù)簡易方便,容易操作,因此大量被運(yùn)用于很多互聯(lián)網(wǎng)Web應(yīng)用中。它在客戶端和傳輸憑據(jù)過程中幾乎沒有做特殊處理,所以在這兩個環(huán)節(jié)尤其要注意對用戶憑據(jù)的保護(hù)。不過,隨著我們對系統(tǒng)的要求越來越復(fù)雜,這樣簡易的實(shí)現(xiàn)方式也有一些明顯的不足。比如,如果不加以封裝,很容易出現(xiàn)在服務(wù)器應(yīng)用程序代碼中出現(xiàn)大量對用戶身份的重復(fù)檢查、錯誤的重定向等;不過最明顯的問題可能是對服務(wù)器會話存儲的依賴,服務(wù)器程序的會話存儲往往在服務(wù)器程序重啟之后丟失,因此可能會導(dǎo)致用戶突然被登出的情況。雖然可以引入單獨(dú)的會話存儲程序來避免這類問題,但引入一個新的中間件就會增加系統(tǒng)的復(fù)雜性。
傳統(tǒng)Web應(yīng)用中身份驗(yàn)證最佳實(shí)踐
上文提到的簡單實(shí)用的登錄技術(shù)已經(jīng)可以幫助建立對用戶身份驗(yàn)證的基本圖景,在一些簡單的應(yīng)用場景中已經(jīng)足夠滿足需求了。然而,用戶鑒權(quán)就是有那種“你可以有很多種方法,就是不怎么優(yōu)雅” 的問題。
最佳實(shí)踐指的是那些經(jīng)過了大量驗(yàn)證、被證明有用的方法。而用戶鑒權(quán)的最佳實(shí)踐就是使用自包含的、含有加密內(nèi)容的 Cookie 作為替代憑據(jù)。其鑒權(quán)過程與上文所提到基于會話標(biāo)識的技術(shù)沒有什么區(qū)別,而主要區(qū)別在于不再頒發(fā)會話標(biāo)識,取而代之的是一個代表身份的、經(jīng)過加密的 “身份 Cookie”。
1. 只在鑒權(quán)請求中發(fā)送一次用戶名和密碼憑據(jù)
2. 成功憑據(jù)之后,由服務(wù)器生成代表用戶身份的 Cookie,發(fā)送給客戶端
3. 客戶端在后續(xù)請求中攜帶上一步中收到的 “身份 Cookie”
4. 服務(wù)器解密”身份 Cookie”,并對需要訪問的資源予以授權(quán)
這樣,我們消除了對服務(wù)器會話存儲的依賴,Cookie本身就有有效期的概念,因此順便能夠輕松提供“記住登錄狀態(tài)”的功能。
另外,由于解密Cookie、既而檢查用戶身份的操作相對繁瑣,工程師不得不考慮對其抽取專門的服務(wù),最終采用了面向切面的模式對身份驗(yàn)證的過程進(jìn)行了封裝,而開發(fā)時只需要使用一些特性標(biāo)注(Attribute Annotation)對特定資源予以標(biāo)記,即可輕松完成身份驗(yàn)證預(yù)處理。
傳統(tǒng)Web應(yīng)用中的單點(diǎn)登錄
單點(diǎn)登錄的需求在向用戶提供多種服務(wù)的企業(yè)普遍存在,出發(fā)點(diǎn)是希望用戶在一個站點(diǎn)中登錄之后,在其他兄弟站點(diǎn)中就不需要再次登錄。
如果多個子站所在的頂級域名一致,基于上文所述的實(shí)踐,可以基于Cookie共享實(shí)現(xiàn)最簡單的單點(diǎn)登錄:在多個子站中使用相同的加密、解密配置,并且在用戶登錄成功后設(shè)置身份 Cookie時將domain值設(shè)置為頂級域名即可。這樣,只要在其中一個網(wǎng)站登錄,其身份 Cookie將在用戶訪問其他子站時也一起帶上。不過實(shí)際情況中,這個方案的應(yīng)用場景很有限,畢竟各個子站使用的用戶數(shù)據(jù)模型可能不完全一致,而加密密鑰多處共享也增加了服務(wù)器應(yīng)用程序的安全風(fēng)險。另外,這種方式與“在多個網(wǎng)站中分別存儲相同的用戶名與密碼”的做法相似,可以說是一種“相同的登錄”(Same Sign-On),而不是“單點(diǎn)登錄”(Single Sign-On)。
對于單點(diǎn)登錄需求來說,域名相同與否并不是最大的挑戰(zhàn),集成登錄系統(tǒng)對各個子站點(diǎn)的系統(tǒng)在設(shè)計上的影響才是。我們希望便利用戶的同時,也期待各個子系統(tǒng)仍擁有獨(dú)立用戶身份、獨(dú)立管理和運(yùn)維的靈活性。因此我們引入獨(dú)立的鑒權(quán)子站點(diǎn)。
當(dāng)用戶到達(dá)業(yè)務(wù)站點(diǎn)A時,被重定向到鑒權(quán)站點(diǎn);登錄成功之后,用戶被重定向回到業(yè)務(wù)站點(diǎn) A、同時附加一個指示“已有用戶登錄”的令牌串——此時業(yè)務(wù)站點(diǎn)A使用令牌串,在服務(wù)器端從鑒權(quán)子站點(diǎn)查詢并記錄當(dāng)前已登錄的用戶。當(dāng)用戶到達(dá)業(yè)務(wù)站點(diǎn)B時,執(zhí)行相同流程。由于已有用戶登錄,所以用戶登錄的過程會被自動省略。
這樣的單點(diǎn)登錄系統(tǒng)能夠較好地解決在多個站點(diǎn)中共享用戶登錄狀態(tài)的需求。不過,如果在編程實(shí)踐過程中略有差池,就會讓用戶陷入巨大的安全風(fēng)險中。例如,在上述重定向過程中,一旦鑒權(quán)系統(tǒng)未能驗(yàn)證返回URL的合法性,就容易導(dǎo)致用戶被釣魚網(wǎng)站利用。在傳統(tǒng)Web應(yīng)用開發(fā)實(shí)踐中,被廣泛部署的身份驗(yàn)證體系是比較重量級的WS-Federation 和 SMAL 等鑒權(quán)協(xié)議和相對輕量級的 OpenID 等技術(shù)。
總結(jié)
本文簡要總結(jié)了在傳統(tǒng)Web應(yīng)用中,被廣泛使用的幾種典型用戶登錄時的鑒權(quán)處理流程。總體來說,在單體 Web 應(yīng)用中,身份驗(yàn)證過程并不復(fù)雜,只要稍加管理,可以較輕松地解決用戶鑒權(quán)的問題。但在傳統(tǒng) Web 應(yīng)用中,為了解決單點(diǎn)登錄的需求,人們也嘗試了多種方式,最終仍然只有使用一些較復(fù)雜的方案才能較好地解決問題。
在現(xiàn)代化 Web 應(yīng)用中,圍繞登錄這一需求,儼然已經(jīng)衍生出了一個新的工程。“登錄工程” 并不簡單,在后續(xù)篇目中將會介紹現(xiàn)代化 Web 應(yīng)用的典型需求及解決方法。
朋友就職于某大型互聯(lián)網(wǎng)公司。前不久,在閑聊間我問他日常工作的內(nèi)容,他說他所在部門只負(fù)責(zé)一件事,即用戶與登錄。
而他的具體工作則是為各個業(yè)務(wù)子網(wǎng)站提供友好的登錄部件(Widget),從而統(tǒng)一整個網(wǎng)站群的登錄體驗(yàn),同時也能令業(yè)務(wù)開發(fā)者不用花費(fèi)額外的精力去關(guān)注用戶鑒權(quán)。這很有趣。
可以看出,在一個現(xiàn)代Web應(yīng)用中,圍繞“登錄”這一需求,儼然已經(jīng)衍生出了一個新的工程。不管是我們面臨的需求,還是解決這些需求所運(yùn)用的方法與工具,都已經(jīng)超出了傳統(tǒng)Web應(yīng)用身份驗(yàn)證技術(shù)的范疇。
在之前一篇文章中,我聊到傳統(tǒng)Web應(yīng)用中的身份驗(yàn)證技術(shù),文章中列出的一些方法在之前很長一段時間內(nèi),為滿足大量的Web應(yīng)用中身份驗(yàn)證的需求提供了思路。在這篇文章里,我將簡要介紹現(xiàn)代Web應(yīng)用中幾種典型的身份驗(yàn)證需求。
形式多樣的鑒權(quán)
考慮這樣一個場景:我們在電腦上登錄了微軟賬號,電腦里的“郵件”應(yīng)用能夠自動同步郵件;我們登錄Web版本的Outlook郵件服務(wù),如果在郵件里發(fā)現(xiàn)了重要的工作安排,將其添加到日歷中,很快電腦里的“日歷”應(yīng)用便能夠?qū)⑦@些日程顯示到Windows桌面上。
這個場景包含了多個鑒權(quán)過程。至少涉及了對Web版本Outlook服務(wù)的鑒權(quán),也涉及了對離線版本的郵件應(yīng)用的鑒權(quán)。要能夠支持同一批用戶既能夠在瀏覽器中登錄,又能夠在移動端或本地應(yīng)用登錄(例如 Windows UWP 應(yīng)用程序),就需要開發(fā)出能夠?yàn)閮煞N應(yīng)用程序服務(wù)的鑒權(quán)體系。
在瀏覽器里,我們通常假設(shè)用戶不信任瀏覽器,用戶通過與服務(wù)器建立的臨時瀏覽器會話完成操作。會話開始時,用戶被重定向到特定頁面進(jìn)行登錄。登錄完成后,用戶通過持續(xù)與服務(wù)器交互來延續(xù)臨時會話的時長;一旦用戶一段時間不與服務(wù)器交互,則他的會話很快就會過期(被服務(wù)器強(qiáng)制登出)。
在移動應(yīng)用中,情況有所不同。相對來說,安裝在移動設(shè)備中的應(yīng)用程序更受用戶信任,移動設(shè)備本身的安全性也比瀏覽器更好。另一方面,將用戶重定向到一個網(wǎng)頁去登錄的做法,并不能提供很好的用戶體驗(yàn)——更重要的是,用戶在使用移動設(shè)備時,時間是碎片化的。我們無法要求用戶必須在特定時間內(nèi)完成操作,也就基本沒有會話的概念:我們需要找到一種能夠安全地在設(shè)備中相對持久地存儲用戶憑據(jù)的方法,并且Web應(yīng)用服務(wù)器可能需要配合這種方式來完成鑒權(quán)。此外,移動設(shè)備也不是絕對安全的,一旦設(shè)備丟失,將給用戶帶來安全風(fēng)險。所以需要在服務(wù)器端提供一種機(jī)制來取消已登錄設(shè)備的訪問權(quán)限。
(圖片來自:http://docs.identityserver.io/en/release/intro/big_picture.html)
方便用戶的多種登錄方式
“輸入用戶名和密碼”作為標(biāo)準(zhǔn)的登錄憑據(jù)被廣泛用于各種登錄場景。不過,在Web應(yīng)用、尤其是互聯(lián)網(wǎng)應(yīng)用中,網(wǎng)站運(yùn)營方越來越發(fā)現(xiàn)使用用戶名作為用戶標(biāo)識確實(shí)給網(wǎng)站提供了便利,但對用戶來說卻并不是那么有幫助:用戶很可能會忘記自己的用戶名。
用戶在使用不同網(wǎng)站的過程中,為了不忘記用戶名,只好使用相同的用戶名。如果恰好在某個網(wǎng)站遇到了該用戶名被占用的情況,他就不得不臨時為這個網(wǎng)站擬一個新的用戶名,于是這個新用戶名很快就被忘記了。
在注冊時,越來越多的網(wǎng)站要求用戶提供電子郵箱地址或者手機(jī)號碼,有的網(wǎng)站還支持讓用戶以多種方式登錄。比如,提供一種讓用戶在使用了一種方式注冊之后,還能綁定其他登錄方式的功能。綁定完成之后,用戶可以選用他喜歡的登錄方式。它隱含了一個網(wǎng)站與用戶共同的認(rèn)知:聯(lián)系方式的擁有者即為用戶本人,這種“從屬”關(guān)系能夠用于證實(shí)用戶的身份。當(dāng)用戶下次在注冊新網(wǎng)站時遇到“郵件地址已被注冊”,或者“手機(jī)號已被注冊”的時候,基本可以確定自己曾經(jīng)注冊過這個網(wǎng)站了。
(圖片來自:http://cargocollective.com/)
另外,登錄過程中所支持的聯(lián)系方式也呈現(xiàn)出多樣性。電子郵件服務(wù)在很多場景中逐漸被形式多樣的其他聯(lián)系方式(比如手機(jī)、微信等)所取代,不少人根本沒有使用郵件的習(xí)慣,如果網(wǎng)站只提供郵箱注冊的途徑,有時候還會遭到那些不經(jīng)常使用電子郵箱的用戶的反感。所以支持多種登錄方式成為了很多網(wǎng)站的迫切需求。
雙因子鑒權(quán):增強(qiáng)型登錄過程
上一節(jié)中提到的“從屬”關(guān)系不光可以幫助用戶判斷自己是否注冊過一個網(wǎng)站,也可以幫助網(wǎng)站在忘記密碼時進(jìn)行臨時認(rèn)證,從而幫助用戶完成新密碼的設(shè)置。如果將這種從屬關(guān)系用于正常登錄過程中的進(jìn)一步驗(yàn)證,就構(gòu)成了雙因子鑒權(quán)。
雙因子鑒權(quán)要求用戶在登錄過程中提供兩種形式不同的憑據(jù),只有兩種驗(yàn)證都成功才能繼續(xù)操作。現(xiàn)代化Web應(yīng)用正在越來越多地使用這種增強(qiáng)型驗(yàn)證方式來保護(hù)關(guān)鍵操作的安全性。例如,查看和修改個人信息,以及修改登錄密碼等。
相信不少人還記得QQ密碼保護(hù)問題的機(jī)制,它使得盜號者即使盜取了QQ密碼,在不知道密碼保護(hù)問題的情況下,也無法修改現(xiàn)有密碼,讓賬號擁有者得以及時挽回?fù)p失。
雙因子的原理在于:兩種驗(yàn)證因子性質(zhì)不一致,冒用身份者同時獲得用戶這兩種信息的機(jī)率十分低,從而能有效地保護(hù)賬號的安全。在QQ密碼保護(hù)的例子里,密碼是一種每次登錄時都會使用的固定文本、相對容易被盜;而密碼保護(hù)問題卻是不怎么頻繁設(shè)置和更改的、隱秘的、個人關(guān)聯(lián)性極強(qiáng)的,不容易被盜。
(圖片來自:http://bit.ly/2kFc492)
現(xiàn)代化Web應(yīng)用形式多樣,設(shè)備種類繁多,場景復(fù)雜多變,而為了更好地保護(hù)用戶賬號的安全,很多應(yīng)用開始將雙因子驗(yàn)證作為登錄過程中的鑒權(quán)步驟。而為了兼具安全和便利的特點(diǎn),一些應(yīng)用還要求運(yùn)用一些優(yōu)化策略以提高用戶體驗(yàn)。比如,僅在用戶在新的設(shè)備上登錄、一段時間未登錄之后的再次登錄、在不常用的地點(diǎn)登錄、修改聯(lián)系信息和密碼、轉(zhuǎn)移賬戶資產(chǎn)等關(guān)鍵操作時要求雙因子鑒權(quán)。
單點(diǎn)登錄:還是需要精心設(shè)計
以前,一般只有大型網(wǎng)站、向用戶提供多種服務(wù)的時候(比如,網(wǎng)易公司運(yùn)營網(wǎng)易門戶和網(wǎng)易郵箱等多種服務(wù)),才會有單點(diǎn)登錄的迫切需求。但在現(xiàn)代化Web系統(tǒng)中,無論是從業(yè)務(wù)的多元化還是從架構(gòu)的服務(wù)化來考慮,對服務(wù)的劃分都更細(xì)致了。
從整個企業(yè)的業(yè)務(wù)模式(例如網(wǎng)易門戶和網(wǎng)易郵箱),到某項業(yè)務(wù)的具體流程(例如京東訂單和京東支付),再到某個流程中的具體步驟(例如短信驗(yàn)證與支付扣款),“服務(wù)”這一概念越來越輕量級,于是人們不得不創(chuàng)造了“微服務(wù)”這個新的品類詞匯來拓展認(rèn)知空間。
(圖片來自:http://cargocollective.com/)
在這整個的演變過程中,出于安全的需要,身份驗(yàn)證的需求都是一直存在的,而且粒度越來越細(xì)。以前我們更關(guān)注用戶在多個子站點(diǎn)的統(tǒng)一登錄體驗(yàn),現(xiàn)在我們還需要關(guān)注用戶在多個子流程中的統(tǒng)一登錄體驗(yàn),以及在多個步驟中的統(tǒng)一登錄體驗(yàn)。而這些流程和步驟,很可能是獨(dú)立的Web系統(tǒng)(微服務(wù)),也有可能是一個用戶界面(獨(dú)立應(yīng)用),還有可能是一個第三方系統(tǒng)(接口集成)。
可以說,單點(diǎn)登錄的需求有增無減,只不過當(dāng)開發(fā)者對這種模式已經(jīng)習(xí)以為常,不再意識到這也是一個能夠?qū)iT討論的話題。
考慮與用戶系統(tǒng)集成,與業(yè)務(wù)系統(tǒng)分離
在討論安全時,分不開的兩個部分就是鑒權(quán)(Authentication)與授權(quán)(Authorization)。
鑒權(quán)的過程是向用戶發(fā)起質(zhì)詢(Challenge),完成身份驗(yàn)證工作。這正是登錄所解決的問題。通常在登錄系統(tǒng)成功識別用戶之后,就會將接下來的工作直接交給業(yè)務(wù)系統(tǒng)來完成。由于各個系統(tǒng)中的授權(quán)模型可能與業(yè)務(wù)形態(tài)有關(guān)系,因此登錄與業(yè)務(wù)系統(tǒng)分離是很自然的設(shè)計。
在對安全要求更嚴(yán)格的企業(yè)或企業(yè)應(yīng)用中,可能需要專門的訪問管理機(jī)制,不過,這樣的做法在互聯(lián)網(wǎng)應(yīng)用中很少見。但在互聯(lián)網(wǎng)Web應(yīng)用中,授權(quán)的范疇也包含一個很小的公有部分,是各個業(yè)務(wù)系統(tǒng)所共有的:即用戶狀態(tài)。我們希望在各業(yè)務(wù)子系統(tǒng)之間共享用戶狀態(tài):用戶被鎖定之后,他在所有業(yè)務(wù)系統(tǒng)都被鎖定;用戶被注銷之后,所有業(yè)務(wù)系統(tǒng)中有關(guān)他的數(shù)據(jù)都被封存。
(圖片來自:http://cargocollective.com/)
另外在多個業(yè)務(wù)系統(tǒng)中,還可能會共用用戶的基本資料和偏好設(shè)置等數(shù)據(jù)。比如,類似于郵件地址這樣的資料,它可以作為登錄憑據(jù),也可以作為一個基本的聯(lián)系方式。如果用戶在一個子系統(tǒng)設(shè)置了偏好語言,其他子系統(tǒng)則直接使用該設(shè)置即可。這樣,開發(fā)一個“用戶”系統(tǒng)的想法也就應(yīng)運(yùn)而生了。由于與用戶的狀態(tài)等基礎(chǔ)信息的關(guān)系很緊密,登錄與用戶系統(tǒng)之間的集成是很自然的,將登錄子系統(tǒng)直接作為這個用戶系統(tǒng)的一部分也不失為一種不錯的實(shí)踐。
與第三方集成:迎接更多用戶
“即得”是一個開放式文檔共享應(yīng)用,特點(diǎn)是“無需登錄,即傳即得”,它利用長時間有效的Cookie來標(biāo)識用戶,從而免除了人們使用應(yīng)用之前必須注冊登錄的繁瑣步驟。
這種做法的風(fēng)險是,如果用戶有及時清理瀏覽器Cookie的習(xí)慣,那很可能導(dǎo)致用戶再一次登錄時不再被識別。不過從這樣一個小例子中,卻容易看出登錄的真正作用,就是Web應(yīng)用識別用戶的過程,當(dāng)下次同一個用戶再次使用時,Web應(yīng)用就能夠知道“這就是上次來過的那個用戶”。
如果識別用戶這一需求能夠在不需要用戶注冊的前提下搞定,豈不兩全齊美?基于第三方身份提供方的接口來識別已經(jīng)在其他平臺注冊的用戶,并將其轉(zhuǎn)化為自己應(yīng)用中的用戶,這種方式完全可行,并且大量的開發(fā)人員已經(jīng)有了豐富的實(shí)踐。
從 2010 年開始就有不少的大型互聯(lián)網(wǎng)公司開始推出開放平臺服務(wù),讓第三方應(yīng)用通過Web接口與這些互聯(lián)網(wǎng)服務(wù)交互,從而為他們提供更豐富多彩的功能。在這個過程中,一些應(yīng)用不為這些平臺提供擴(kuò)展,卻巧辟蹊徑地利用了這些開放平臺的身份識別接口來免除新用戶注冊的過程,從而為自己的產(chǎn)品快速導(dǎo)入用戶。不少網(wǎng)站都提供“使用微博賬號登錄”功能,相信讀者一定體驗(yàn)過。
(圖片來自:http://bit.ly/2kFi3e8)
如果你的應(yīng)用需要向第三方提供用戶,那么我們的角色就由“從上下文中讀取用戶身份”變成了“向上下文中寫入用戶身份”了。如果你正好有過與各互聯(lián)網(wǎng)公司開放平臺的接口打交道的經(jīng)歷,這時候,你就可以體驗(yàn)一把提供開放、安全上下文的挑戰(zhàn)了。如果……你的平臺既希望讓其他平臺的用戶能夠平滑接入,又希望向其他平臺公開自己的用戶,那可能是另一番更有趣的挑戰(zhàn)。這個過程,也可以作為生物驗(yàn)證之外的另一種間接消除密碼的實(shí)踐方式吧。
登錄,現(xiàn)在實(shí)實(shí)在在地成為了一個獨(dú)立的工程。尤其在形態(tài)多樣的基于Web的應(yīng)用,以及這些Web應(yīng)用本身所依賴的各色后端服務(wù)快速生長的過程中,各種鑒權(quán)需求隨之而來。如何在保障各個環(huán)節(jié)中安全的同時,又為用戶提供良好的體驗(yàn),成為一個挑戰(zhàn)。
另外,個人信息泄露的事件頻繁被曝光,它們導(dǎo)致的社會問題也開始被更多人關(guān)注和重視,作為IT系統(tǒng)支撐者的工程師們有責(zé)任了解事關(guān)安全的基礎(chǔ)知識,并掌握必要的技能去保護(hù)用戶數(shù)據(jù)和企業(yè)利益。
我會在接下來的文章中介紹解決典型登錄需求的具體技術(shù)方案,以及相關(guān)領(lǐng)域的安全實(shí)踐常識。
登錄系統(tǒng)
首先,我們要為“登錄”做一個簡要的定義,令后續(xù)的講述更準(zhǔn)確。之前的兩篇文章有意無意地混淆了“登錄”與“身份驗(yàn)證”的說法,因?yàn)樵诒酒埃簧佟皞鹘y(tǒng)Web應(yīng)用”都將對身份的識別看作整個登錄的過程,很少出現(xiàn)像企業(yè)應(yīng)用環(huán)境中那樣復(fù)雜的情景和需求。但從之前的文章中我們看到,現(xiàn)代Web應(yīng)用對身份驗(yàn)證相關(guān)的需求已經(jīng)向復(fù)雜化發(fā)展了。
我們有必要重新認(rèn)識一下登錄系統(tǒng)。登錄指的是從識別用戶身份,到允許用戶訪問其權(quán)限相應(yīng)的資源的過程。舉個例子,在網(wǎng)上買好了票之后去影院觀影的過程就是一個典型的登錄過程:我們先去取票機(jī),輸入驗(yàn)證碼取票;接著拿到票去影廳檢票進(jìn)入。取票的過程即身份驗(yàn)證,它能夠證明我們擁有這張票;而后面檢票的過程,則是授權(quán)訪問的過程。之所以要分成這兩個過程,最直接的原因還是業(yè)務(wù)形態(tài)本身具有復(fù)雜性——如果觀景過程是免費(fèi)匿名的,也就免去了這些過程。
在登錄的過程中,“鑒權(quán)”與“授權(quán)”是兩個最關(guān)鍵的過程。接下來要介紹的一些技術(shù)和實(shí)踐,也包含在這兩個方面中。雖然現(xiàn)代Web應(yīng)用的登錄需求比較復(fù)雜,但只要處理好了鑒權(quán)和授權(quán)兩個方面,其余各個方面的問題也將迎刃而解。在現(xiàn)代Web應(yīng)用的登錄工程實(shí)踐中,需要結(jié)合傳統(tǒng)Web應(yīng)用的典型實(shí)踐,以及一些新的思路,才能既解決好登錄需求,又能符合Web的輕量級架構(gòu)思路。
解析常見的登錄場景
在簡單的Web系統(tǒng)中,典型的鑒權(quán)也就是要求用戶輸入并比對用戶名和密碼的過程,而授權(quán)則是確保會話Cookie存在。而在稍微復(fù)雜的Web系統(tǒng)中,則需要考慮多種鑒權(quán)方式,以及多種授權(quán)場景。上一篇文章中所述的“多種登錄方式”和“雙因子鑒權(quán)”就是多種鑒權(quán)方式的例子。有經(jīng)驗(yàn)的人經(jīng)常調(diào)侃說,只要理解了鑒權(quán)與授權(quán),就能清晰地理解登錄系統(tǒng)了。不光如此,這也是安全登錄系統(tǒng)的基礎(chǔ)所在。
鑒權(quán)的形式豐富多彩,有傳統(tǒng)的用戶名密碼對、客戶端證書,有人們越來越熟悉的第三方登錄、手機(jī)驗(yàn)證,以及新興的掃碼和指紋等方式,它們都能用于對用戶的身份進(jìn)行識別。在成功識別用戶之后,在用戶訪問資源或執(zhí)行操作之前,我們還需要對用戶的操作進(jìn)行授權(quán)。
在一些特別簡單的情形中——用戶一經(jīng)識別,就可以無限制地訪問資源、執(zhí)行所有操作——系統(tǒng)直接對所有“已登錄的人”放行。比如高速公路收費(fèi)站,只要車輛有合法的號牌即可放行,不需要給駕駛員發(fā)一張用于指示“允許行駛的方向或時間”的票據(jù)。除了這類特別簡單的情形之外,授權(quán)更多時候是比較復(fù)雜的工作。
在單一的傳統(tǒng)Web應(yīng)用中,授權(quán)的過程通常由會話Cookie來完成——只要服務(wù)器發(fā)現(xiàn)瀏覽器攜帶了對應(yīng)的Cookie,即允許用戶訪問資源、執(zhí)行操作。而在瀏覽器之外,例如在Web API調(diào)用、移動應(yīng)用和富 Web 應(yīng)用等場景中,要提供安全又不失靈活的授權(quán)方式,就需要借助令牌技術(shù)。
令牌
令牌是一個在各種介紹登錄技術(shù)的文章中常被提及的概念,也是現(xiàn)代Web應(yīng)用系統(tǒng)中非常關(guān)鍵的技術(shù)。令牌是一個非常簡單的概念,它指的是在用戶通過身份驗(yàn)證之后,為用戶分配的一個臨時憑證。在系統(tǒng)內(nèi)部,各個子系統(tǒng)只需要以統(tǒng)一的方式正確識別和處理這個憑證即可完成對用戶的訪問和操作進(jìn)行授權(quán)。在上文所提到的例子中,電影票就是一個典型的令牌。影廳門口的工作人員只需要確認(rèn)來客手持印有對應(yīng)場次的電影票即視為合法訪問,而不需要理會客戶是從何種渠道取得了電影票(比如自行購買、朋友贈予等),電影票在本場次范圍內(nèi)可以持續(xù)使用(比如可以中場出去休息等)、過期作廢。通過電影票這樣一個簡單的令牌機(jī)制,電影票的出售渠道可以豐富多樣,檢票人員的工作卻仍然簡單輕松。
從這個例子也可以看出令牌并非什么神奇的機(jī)制,只是一種很常見的做法。還記得第一篇文章中所述的“自包含的Cookie”嗎?那實(shí)際上就是一個令牌而已,而且在令牌中寫有關(guān)于有效性的內(nèi)容——正如一個電影票上會寫明場次與影廳編號一樣。可見,在Web安全系統(tǒng)中引入令牌的做法,有著與傳統(tǒng)場合一樣的妙用。在安全系統(tǒng)中,令牌經(jīng)常用于包含安全上下文信息,例如被識別的用戶信息、令牌的頒發(fā)來源、令牌本身的有效期等。另外,在必要時可以由系統(tǒng)廢止令牌,在它下次被使用用于訪問、操作時,用戶被禁止。
由于令牌有這些特殊的妙用,因此安全行業(yè)對令牌標(biāo)準(zhǔn)的制定工作一直沒有停止過。在現(xiàn)代化Web系統(tǒng)的演進(jìn)過程中,流行的方式是選用基于Web技術(shù)的“簡單”的技術(shù)來代替相對復(fù)雜、重量級的技術(shù)。典型地,比如使用JSON-RPC或REST接口代替了SOAP格式的服務(wù)調(diào)用,用微服務(wù)架構(gòu)代替了SOA架構(gòu)等等。而適用于Web技術(shù)的令牌標(biāo)準(zhǔn)就是Json Web Token(JWT),它規(guī)范了一種基于JSON的令牌的簡單格式,可用于安全地封裝安全上下文信息。
OAuth 2、Open ID Connect
令牌在廣為使用的OAuth技術(shù)中被采用來完成授權(quán)的過程。OAuth是一種開放的授權(quán)模型,它規(guī)定了一種供資源擁有方與消費(fèi)方之間簡單又直觀的交互方法,即從消費(fèi)方向資源擁有方發(fā)起使用AccessToken(訪問令牌)簽名的HTTP請求。這種方式讓消費(fèi)方應(yīng)用在無需(也無法)獲得用戶憑據(jù)的情況下,只要用戶完成鑒權(quán)過程并同意消費(fèi)方以自己的身份調(diào)用數(shù)據(jù)和操作,消費(fèi)方就可以獲得能夠完成功能的訪問令牌。OAuth簡單的流程和自由的編程模型讓它很好地滿足了開放平臺場景中授權(quán)第三方應(yīng)用使用用戶數(shù)據(jù)的需求。不少互聯(lián)網(wǎng)公司建設(shè)開放平臺,將它們的用戶在其平臺上的數(shù)據(jù)以 API 的形式開放給第三方應(yīng)用來使用,從而讓用戶享受更豐富的服務(wù)。
OAuth在各個開放平臺的成功使用,令更多開發(fā)者了解到它,并被它簡單明確的流程所吸引。此外,OAuth協(xié)議規(guī)定的是授權(quán)模型,并不規(guī)定訪問令牌的數(shù)據(jù)格式,也不限制在整個登錄過程中需要使用的鑒權(quán)方法。人們很快發(fā)現(xiàn),只要對OAuth進(jìn)行合適的利用即可將其用于各種自有系統(tǒng)中的場景。例如,將 Web 服務(wù)視作資源擁有方,而將富Web應(yīng)用或者移動應(yīng)用視作消費(fèi)方應(yīng)用,就與開放平臺的場景完全吻合。
另一個大量實(shí)踐的場景是基于OAuth的單點(diǎn)登錄。OAuth并沒有對鑒權(quán)的部分做規(guī)定,也不要求在握手交互過程中包含用戶的身份信息,因此它并不適合作為單點(diǎn)登錄系統(tǒng)來使用。然而,由于OAuth的流程中隱含了鑒權(quán)的步驟,因而仍然有不少開發(fā)者將這一鑒權(quán)的步驟用作單點(diǎn)登錄系統(tǒng),這也儼然衍生成為一種實(shí)踐模式。更有人將這個實(shí)踐進(jìn)行了標(biāo)準(zhǔn)化,它就是Open ID Connect——基于OAuth的身份上下文協(xié)議,通過它即可以JWT的形式安全地在多個應(yīng)用中共享用戶身份。接下來,只要讓鑒權(quán)服務(wù)器支持較長的會話時間,就可以利用OAuth為多個業(yè)務(wù)系統(tǒng)提供單點(diǎn)登錄功能了。
我們還沒有討論OAuth對鑒權(quán)系統(tǒng)的影響。實(shí)際上,OAuth對鑒權(quán)系統(tǒng)沒有影響,在它的框架內(nèi),只是假設(shè)已經(jīng)存在了一種可用于識別用戶的有效機(jī)制,而這種機(jī)制具體是怎么工作的,OAuth并不關(guān)心。因此我們既可以使用用戶名密碼(大多數(shù)開放平臺提供商都是這種方式),也可以使用掃碼登錄來識別用戶,更可以提供諸如“記住密碼”,或者雙因子驗(yàn)證等其他功能。
匯總
上面羅列了大量術(shù)語和解釋,那么具體到一個典型的Web系統(tǒng)中,又應(yīng)該如何對安全系統(tǒng)進(jìn)行設(shè)計呢?綜合這些技術(shù),從端到云,從Web門戶到內(nèi)部服務(wù),本文給出如下架構(gòu)方案建議:
推薦為整個應(yīng)用的所有系統(tǒng)、子系統(tǒng)都部署全程的HTTPS,如果出于性能和成本考慮做不到,那么至少要保證在用戶或設(shè)備直接訪問的Web應(yīng)用中全程使用HTTPS。
用不同的系統(tǒng)分別用作身份和登錄,以及業(yè)務(wù)服務(wù)。當(dāng)用戶登錄成功之后,使用OpenID Connect向業(yè)務(wù)系統(tǒng)頒發(fā)JWT格式的訪問令牌和身份信息。如果需要,登錄系統(tǒng)可以提供多種登錄方式,或者雙因子登錄等增強(qiáng)功能。作為安全令牌服務(wù)(STS),它還負(fù)責(zé)頒發(fā)、刷新、驗(yàn)證和取消令牌的操作。在身份驗(yàn)證的整個流程的每一個步驟,都使用OAuth及JWT中內(nèi)置的機(jī)制來驗(yàn)證數(shù)據(jù)的來源方是可信的:登錄系統(tǒng)要確保登錄請求來自受認(rèn)可的業(yè)務(wù)應(yīng)用,而業(yè)務(wù)在獲得令牌之后也需要驗(yàn)證令牌的有效性。
在Web頁面應(yīng)用中,應(yīng)該申請時效較短的令牌。將獲取到的令牌向客戶端頁面中以httponly的方式寫入會話Cookie,以用于后續(xù)請求的授權(quán);在后緒請求到達(dá)時,驗(yàn)證請求中所攜帶的令牌,并延長其時效。基于JWT自包含的特性,輔以完備的簽名認(rèn)證,Web 應(yīng)用無需額外地維護(hù)會話狀態(tài)。
在富客戶端Web應(yīng)用(單頁應(yīng)用),或者移動端、客戶端應(yīng)用中,可按照應(yīng)用業(yè)務(wù)形態(tài)申請時效較長的令牌,或者用較短時效的令牌、配合專用的刷新令牌使用。
在Web應(yīng)用的子系統(tǒng)之間,調(diào)用其他子服務(wù)時,可靈活使用“應(yīng)用程序身份”(如果該服務(wù)完全不直接對用戶提供調(diào)用),或者將用戶傳入的令牌直接傳遞到受調(diào)用的服務(wù),以這種方式進(jìn)行授權(quán)。各個業(yè)務(wù)系統(tǒng)可結(jié)合基于角色的訪問控制(RBAC)開發(fā)自有專用權(quán)限系統(tǒng)。
作為工程師,我們不免會考慮,既然登錄系統(tǒng)的需求可能如此復(fù)雜,而大家面臨的需求在很多時候又是如此類似,那么有沒有什么現(xiàn)成(Out of Box)的解決方案呢?自然是有的。IdentityServer是一個完整的開發(fā)框架,提供了普通登錄到OAuth和Open ID Connect的完整實(shí)現(xiàn);Open AM是一個開源的單點(diǎn)登錄與訪問管理軟件平臺;而Microsoft Azure AD和AWS IAM則是公有云上的身份服務(wù)。幾乎在各個層次都有現(xiàn)成的方案可用。使用現(xiàn)成的產(chǎn)品和服務(wù),能夠極大地縮減開發(fā)成本,尤其為創(chuàng)業(yè)團(tuán)隊快速構(gòu)建產(chǎn)品和靈活變化提供更有力的保障。
本文簡單解釋了登錄過程中所涉及的基本原理,以及現(xiàn)代Web應(yīng)用中用于身份驗(yàn)證的幾種實(shí)用技術(shù),希望為您在開發(fā)身份驗(yàn)證系統(tǒng)時提供幫助。現(xiàn)代Web應(yīng)用的身份驗(yàn)證需求多變,應(yīng)用本身的結(jié)構(gòu)也比傳統(tǒng)的Web應(yīng)用更復(fù)雜,需要架構(gòu)師在明確了登錄系統(tǒng)的基本原理的基礎(chǔ)之上,靈活利用各項技術(shù)的優(yōu)勢,恰到好處地解決問題。
什么我們把網(wǎng)站驗(yàn)證到百度搜索資源平臺
百度搜索資源平臺推薦站長添加主站(您網(wǎng)站的鏈接也許會使用www 和非 www 兩種網(wǎng)址,建議添加用戶能夠真實(shí)訪問到的網(wǎng)址),添加并驗(yàn)證后,可證明您是該域名的擁有者,可以快捷批量添加子站點(diǎn),查看所有子站數(shù)據(jù),無需再一一驗(yàn)證您的子站點(diǎn)。
如何驗(yàn)證網(wǎng)站
首先如果您的網(wǎng)站已使用了百度統(tǒng)計,您可以使用統(tǒng)計賬號登錄平臺,或者綁定站長平臺與百度統(tǒng)計賬號,站長平臺支持您批量導(dǎo)入百度統(tǒng)計中的站點(diǎn),您不需要再對網(wǎng)站進(jìn)行驗(yàn)證。
百度站長平臺為未使用百度統(tǒng)計的站點(diǎn)提供三種驗(yàn)證方式:文件驗(yàn)證、html標(biāo)簽驗(yàn)證、CNAME驗(yàn)證。
1.文件驗(yàn)證:您需要下載驗(yàn)證文件,將文件上傳至您的服務(wù)器,放置于域名根目錄下。
2.html標(biāo)簽驗(yàn)證:將html標(biāo)簽添加至網(wǎng)站首頁html代碼的標(biāo)簽與標(biāo)簽之間。
3.CNAME驗(yàn)證:您需要登錄域名提供商或托管服務(wù)提供商的網(wǎng)站,添加新的DNS記錄。
驗(yàn)證完成后,我們將會認(rèn)為您是網(wǎng)站的擁有者。為使您的網(wǎng)站一直保持驗(yàn)證通過的狀態(tài),請保留驗(yàn)證的文件、html標(biāo)簽或CNAME記錄,我們會去定期檢查驗(yàn)證記錄
網(wǎng)站驗(yàn)證常見錯誤及解決辦法
*請認(rèn)真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。