如何構建身份和訪問管理(IAM)服務part1
2. 使用Auth0構建基於雲的IAM服務Auth0是一個基於雲的平台,提供身份訪問管理服務,幫助開發人員通過定制的IAM服務增強其應用程序。
當使用Auth0 配置我們自己的IAM 解決方案時,我們不需要託管和支持環境。此外,該服務還提供一些現成的用戶表單,包括登錄表單。您可以使用Auth0 儀表板手動完成大部分配置。
Auth0免費提供了7000個用戶的配額,所以根據我們的要求,我們可以免費集成。但是,這樣的選項有局限性:
不支持多個企業。好的一面是,我們仍然可以創建多個API,每個API 具有單獨的權限,並將它們視為企業。
不支持通過社交媒體服務進行連接。
與自定義數據庫的連接不可用,這意味著沒有舊數據庫支持,也沒有自我備份。
每月只有1000 個機器對機器令牌可用,當我們想要以編程方式管理所有內容時,這可能是一個問題。
要開始使用Auth0,您需要使用Auth0 註冊表創建管理員配置文件並轉到Auth0 儀表板。 Auth0 管理儀表板提供了很多選項,但開始集成的最低要求包括以下內容:
已創建的應用程序
已創建的API 和權限
Auth0 應用程序保存憑據(clientId和clientSecret,它們是身份驗證和授權流程的一部分)並包含多個API。
API分為兩種類型:
系統API,供後端服務器或執行管理任務的受信任方使用。一般來說,任何可以通過Auth0儀表板完成的事情也可以通過這個API完成。系統API 是默認創建的,包含管理IAM 儀表板服務器端所需的一組預定義權限。
公共API,供前端和不受信任方使用。公共API可以手動創建,包含系統權限以及自定義權限。
我們將使用生成的基本URL (https://dev-mt-ji-7q.us.auth0.com/) 和一個名為https://example.com 的API 創建一個應用程序,以供進一步用於演示目的。
2.1.驗證要配置身份驗證機制,您可以使用自定義或預定義的登錄表單。讓我們探討一下這兩個選項。
2.1.1.使用自定義登錄表單使用自定義登錄表單的過程稱為資源所有者密碼流程。它的工作原理如下:
用戶單擊“登錄”並輸入其登錄名和密碼。
任何應用程序都可以將用戶的登錄名和密碼發送到我們的Auth0 應用程序(/oauth/token 端點),其基本URL 是在儀表板中創建的應用程序的URL (https://dev-mt-ji-7q.us.auth0 .com/)。該URL 將在創建過程中生成。
我們的Auth0 應用程序檢查登錄名和密碼。
我們的Auth0 應用程序返回一個訪問令牌和一個刷新令牌。
現在網站可以使用Access Token調用API服務器來訪問資源。
對於資源所有者密碼流程,我們需要啟用密碼授予類型,默認情況下禁用該類型。身份驗證可以通過向IAM 提供商(即auth0 API 服務器)發出單個請求來實現。這種方法的唯一缺點是,發送到後端的憑據可以存儲起來以供將來使用,然後再交換為訪問令牌,這帶來了潛在洩漏的可能性。
為了確保登錄流程的安全,必須使用MFA。但在使用MFA API 之前,我們需要為應用程序啟用MFA授權類型。為此,請轉至應用程序- 選擇我們的應用程序- 高級設置- 授予類型,然後選中密碼和MFA複選框。
屏幕截圖1. 啟用MFA 授予類型
接下來要做的就是轉到“設置”-“API 授權設置”,然後在“默認目錄”字段中輸入“用戶名-密碼-身份驗證” ,然後單擊“保存”。
屏幕截圖2. 填寫默認目錄字段
現在確保身份驗證過程的一切都已準備就緒,讓我們探索一下MFA 的詳細登錄流程:
這樣的流程涉及向用戶發送挑戰的用戶驗證器。所有請求都應從我們的外部API 服務器發出。為了更好地理解上述方案,我們總結一下可能的場景:
如果禁用MFA,則oauth/token端點將返回JWT。下面顯示的步驟1 將直接引導至JWT。
如果啟用了MFA 但尚未關聯身份驗證器,我們將執行以下步驟:
步驟1:請求token,之後服務器會收到error mfa_required。
步驟2:請求觸髮質詢所需的用戶身份驗證器。
步驟3:將驗證器與Auth0關聯。 API 服務器接收臨時代碼,用戶接收一次性密碼(OTP),這是步驟3a。
步驟3b:使用服務器代碼和用戶的OTP 代碼重複令牌請求。
如果啟用了MFA 並且已關聯身份驗證器,我們將執行以下步驟:
步驟1:請求令牌,之後服務器將收到錯誤mfa_required。
步驟2:請求用戶身份驗證器觸髮質詢。
步驟3:將驗證器與Auth0關聯,服務器將收到錯誤,因為驗證器已經關聯。此處未觸發步驟3a,因為用戶尚未獲得OTP。
步驟4:請求用戶質詢,這會返回服務器的臨時代碼,將OTP 發送給用戶(步驟4a),並使用服務器代碼和用戶的OTP 代碼重複令牌請求(步驟4b)。在進一步的授權嘗試中,可以省略步驟3。
現在,讓我們通過代碼示例詳細探討這些步驟:
步驟1.向/oauth/token端點發送請求。如果沒有MFA,此端點應立即返回JWT。如果啟用了MFA,系統將提示用戶通過挑戰。
varaxios=require('axios').default;
varoptions={
method:'POST',
url:'https://dev-mt-ji-7q.us.auth0.com/oauth/token',//https://dev-mt-ji-7q.us.auth0.comisgeneratedafterapplicationcreation
headers:{'content-type':'application/x-www-form-urlencoded'},
data:newURLSearchParams({
grant_type:'password',//authenticationbyuserpassword
username:'user@example.com',
password:'pwd',
client_id:'vFqyrkC6qz6gUyhPqL6rXBTjkY8jyN9a',//applicationclientid
client_secret:'YOUR_CLIENT_SECRET',//applicationsecret
audience:'https://example.com',//thisistheAPIthatwascreatedearlier
scope:'email'
})
};
axios.request(options).then(function(response){
console.log(response.data);
}).catch(function(error){
console.error(error);
});如果啟用了MFA,響應將包含mfa_required錯誤和mfa_token。然後,我們需要請求可用的MFA 用戶身份驗證器。
步驟2.使用以下代碼獲取MFA 身份驗證器:
varoptions={
method:'GET',
url:'https://dev-mt-ji-7q.us.auth0.com/mfa/authenticators',
headers:{authorization:'BearerMFA_TOKEN','content-type':'application/json'}
};
axios.request(options).then(function(response){
console.log(response.data);
}).catch(function(error){
console.error(error);
});現在,讓我們獲取一個包含用戶可用身份驗證器的數組:
[
{
'id':'email|dev_NU1Ofuw3Cw0XCt5x',
'authenticator_type':'oob',
'active':true,
'oob_channel':'email',
'name':'email@address.com'
}
]步驟3:每種身份驗證器類型註冊一次身份驗證器。
以下是如何發出請求並將身份驗證器與API 關聯:
varoptions={
method:'POST',
url:'https://dev-mt-ji-7q.us.auth0.com/mfa/associate',
headers:{authorization:'BearerMFA_TOKEN','content-type':'application/json'},
data:{authenticator_types:['oob'],oob_channels:['sms'],phone_number:'+11.9'}
};
axios.request(options).then(function(response){
console.log(response.data);
}).catch(function(error){
console.error(error);
});如果之前未啟用身份驗證器,我們將收到響應代碼,並且用戶將收到OTP:
{
'authenticator_type':'oob',
'binding_method':'prompt',
'recovery_codes':['N3BGPZZWJ85JLCNPZBDW6QXC'],
'oob_channel':'sms',
'oob_code':'ata6daXAiOi.'
}然後應將OTP 和代碼提供給oauth/token(步驟3b)。
如果身份驗證器已關聯,我們將收到錯誤並轉至質詢端點(請參閱步驟4)。
步驟4:向用戶發送挑戰:
varoptions={
method:'POST',
url:'https://dev-mt-ji-7q.us.auth0.com/mfa/challenge',
data:{
client_id:'YOUR_CLIENT_ID',
client_secret:'YOUR_CLIENT_SECRET',
challenge_type:'oob',
authenticator_id:'sms|dev_NU1Ofuw3Cw0XCt5x',
mfa_token:'MFA_TOKEN'
}
};
axios.request(options).then(function(response){
console.log(response.data);
}).catch(function(error){
console.error(error);
});
Whenchallengeispassed,theuserreceiversotpcode(4a)andgoestostep4b步驟3b/4b:在上一步(3a 或4a)之後,用戶將收到應提供給/oauth/token的OTP 代碼:
varoptions={
method:'POST',
url:'https://dev-mt-ji-7q.us.auth0.com/oauth/token',
headers:{
authorization:'BearerMFA_TOKEN',
'content-type':'application/x-www-form-urlencoded'
},
data:newURLSearchParams({
grant_type:'http://auth0.com/oauth/grant-type/mfa-oob',
client_id:'vFqyrkC6qz6gUyhPqL6rXBTjkY8jyN9a',
client_secret:'YOUR_CLIENT_SECRET',
mfa_token:'MFA_TOKEN',
oob_code:'OOB_CODE',
binding_code:'USER_OTP_CODE'
})
};
axios.request(options).then(function(response){
console.log(response.data);
}).catch(function(error){
console.error(error);
});作為響應,我們將收到JWT:
{
'id_token':'eyJ.i',
'access_token':'eyJ.i',
'expires_in':600,
'scope':'openidprofile',
'token_type':'Bearer'
}
Note:Steps3band4barethesamestepinpracticebuthavebeensplitintodifferentstepsheretofacilitatebetterunderstandingoftheauthorizationflow(seeschemeAloginflowwithMFA).2.1.2.使用預定義的登錄表單要使用預定義的登錄表單,我們需要遵循授權代碼流程。在這種情況下,我們從端點請求授權代碼/authorize並將其傳遞redirect_url給Auth0。系統將提示用戶使用Auth0 表單登錄。成功登錄後,用戶將被重定向到我們的API,該API 將用授權代碼交換JWT 令牌。
獲取代碼的方法如下:
varoptions={
method:'POST',
url:'https://dev-mt-ji-7q.us.auth0.com/authorize',
headers:{
authorization:'BearerMFA_TOKEN',
'content-type':'application/x-www-form-urlencoded'
},
data:newURLSearchParams({
response_type:'code',
client_id:'vFqyrkC6qz6gUyhPqL6rXBTjkY8jyN9a'
connection:null(Auth0loginformwillbeprompted),
redirect_uri:'linktoapplicationwhichwillreceiveauthcode',
})
};
axios.request(options).then(function(response){
console.log(response.data);
}).catch(function(error){
console.error(error);
});以下是獲取代碼令牌的方法:
varoptions={
method:'POST',
url:'https://dev-mt-ji-7q.us.auth0.com/oauth/token',
headers:{
authorization:'BearerMFA_TOKEN',
'content-type':'application/x-www-form-urlencoded'
},
data:newURLSearchParams({
grant_type:'authorization_code',
client_id:'vFqyrkC6qz6gUyhPqL6rXBTjkY8jyN9a',
client_secret:'YOUR_CLIENT_SECRET',
code:'authcode',
})
};
axios.request(options).then(function(response){
console.log(response.data);
}).catch(function(error){
console.error(error);
});2.2.授權為了構建授權流程,我們可以使用express-oauth2-jwt-bearerSDK。
它需要在使用受眾(https://example.com) 和發行者URL (https://dev-mt-ji-7q.us.auth0.com) 初始化的外部API 服務器上創建中間件。中間件從標頭開始檢查承載。為了額外檢查令牌中實體的權限,我們可以使用express-oauth2-jwt-bearer SDK配置中間件以進行範圍檢查。
constexpress=require('express');
constapp=express();
const{auth,requiredScopes}=require('express-oauth2-jwt-bearer');
//Authorizationmiddleware.Whenused,theAccessTokenmust
//existandbeverifiedagainsttheAuth0JSONWebKeySet.
constcheckJwt=auth({
audience:'https://example.com',
issuerBaseURL:'https://dev-mt-ji-7q.us.auth0.com/',
});
//Thisrouteneedsauthentication
app.get('/api/private',checkJwt,function(req,res){
res.json({
message:'Hellofromaprivateendpoint!Youneedtobeauthenticatedtoseethis.'
});
});
constcheckScopes=requiredScopes('get:users');
app.get('/api/users',checkJwt,checkScopes,function(req,res){
constauth=req.auth;
constuserData=awaitUserDAO.getById(auth.payload.sub);
res.json(userData);
});
app.listen(3000,function(){
console.log
}身份驗證過程很簡單,因為我們可以完全依賴Auth0 API 來檢查令牌和權限。
2.3.RBACAuth0 提供兩種方法來確保基於角色的訪問控制:
使用授權核心
使用RBAC 擴展
當我們使用授權核心時,Auth0 允許我們為在Auth0 中創建的API 啟用RBAC。要啟用RBAC 功能,我們可以使用儀表板或管理API(以編程方式)。
使用授權核心方案我們需要做以下事情:
在Auth0 應用程序中註冊API
在API中創建自定義權限(就Auth0而言,每個界定不同外部服務的API都有自己的一組權限)
創建自定義角色
為角色分配權限
為用戶分配角色
直接為用戶分配權限
我們可以通過儀表板或以編程方式創建和分配角色和權限。如果需要在授權過程中驗證角色和權限,則可以將角色和權限包含在令牌中。
除了核心授權方法之外,RBAC 擴展還創建另一種類型的資源,稱為組和規則:
規則是用作授權掛鉤的任意JavaScript 代碼,可用於在對用戶進行身份驗證時擴展默認授權行為。啟用的規則將在身份驗證過程的最後一步執行。規則可用於在某些情況下拒絕特定用戶的訪問或向第三方服務索取信息。
組是用戶的部門。
您可以在Auth0 網站上了解有關RBAC 擴展的更多信息。
2.4.暴力破解和機器人保護暴力保護可保護企業免受單個IP 地址攻擊單個用戶帳戶的影響。當同一IP 地址多次嘗試以同一用戶身份登錄但失敗時,暴力保護會執行以下操作:
向受影響的用戶發送電子郵件
阻止可疑IP 地址以該用戶身份登錄
暴力保護適用於所有用戶,包括租戶管理員。如果某個IP 地址由於暴力保護而被阻止,它將保持被阻止狀態,直到發生以下事件之一:
管理員刪除該塊
管理員提高登錄門檻
30天通行證
受影響的用戶選擇電子郵件通知中的取消阻止鏈接(如果已配置)
受影響的用戶更改了密碼(在所有鏈接的帳戶上)
您可以在Auth0 儀表板中激活和自定義暴力破解和機器人保護功能。
2.5.審核日誌Auth0 使您能夠從儀表板查看所有與租戶相關的日誌,並通過鉤子實時收集一些日誌。
目前Hooks僅支持用戶預註冊、用戶後註冊等基本操作。要將所有可能的日誌發送到外部存儲,
Recommended Comments