在公司遇到一個需求,同事希望能夠從A專案透過連結開啟B專案裡某隻程式時,可以不用再登入一次。我第一個想法是做SSO,但公司目前的開發框架並沒有相關功能,加上專案有時程壓力,最後決定使用token驗證來跳過B專案的登入步驟。
在動手之前查了許多資料,幾乎都不建議把access_token放在url中傳送,因為放在url的話很容易在傳送的過程中將token外洩。目前是先將token的有效期限設的很短,之後有時間的話會考慮把token改為一次性驗證。
token產生的部分我是使用ASP.NET OWIN Bearer Token,只要在Controller加上authorize attribute,再把token塞進request header中,系統就會幫你驗證了。但這次是要用連結開啟,window.open()沒辦法把token塞進header。雖然有查到可以用jquery的get去把html取回來後塞進新視窗,但我不打算這麼做,最後決定從站台驗證的那段下手。
原本是希望能找到能改抓url中access_token的設定,但找了一陣子都沒看到相關的設定,只好寫個自訂的authorize attribute。
public class UrlTokenAuthorize : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
//取得url中的access_token
var token = httpContext.Request.Params.Get("access_token");
if (!string.IsNullOrEmpty(token))
{
//將token解密
var ticket = Startup.OAuthOptions.AccessTokenFormat.Unprotect(token);
//檢查token是否過期
if (ticket.Properties.ExpiresUtc?.DateTime < DateTime.Now.ToUniversalTime())
{
return false;
}
//手動將token塞進httpContext中,此時IsAuthenticated會變為true
httpContext.User = new ClaimsPrincipal(ticket.Identity);
}
return httpContext.User.Identity.IsAuthenticated;
}
}
參考資料: