標籤:add 中間 blank task 中介軟體 一行代碼 ice create cookie
NET Core 2.0使用Cookie認證實現SSO單點登入
之前寫了一個使用ASP.NET MVC實現SSO登入的Demo,https://github.com/bidianqing/SSO.Sample,這個Demo是基於.NET Framework,.NET Core 2.0出來了試著使用ASP.NET Core嘗試一下。假如我們有三個網站
- domain.dev
- order.domain.dev
- passport.domain.dev
domain.dev作為我們的主站肯定是可以匿名訪問的,當點擊登入按鈕的時候就會跳轉到passport.domain.dev,完成登入後跳回domain.dev。order.domain.dev肯定是不可以匿名訪問的必須登入才能訪問,所以直接跳轉到passport.domain.dev,完成登入後跳回order.domain.dev。passport作為我們的認證系統,只要登入成功,其他各個系統(例如order,news,)都是登入狀態,大概就是實現這麼一個功能。
好,開啟VisualStudio,哦,對了 VS 2017已經從15.3→15.3.3了,大家可以去升級
先建立三個ASP.NET Core項目,等會我們把這三個項目部署到IIS裡去,並修改hosts檔案,用網域名稱去訪問
對於每個項目我們都需要在Configure和ConfigureServices兩個方法中寫一些代碼,另外Portal和Order不提供登入功能,但是提供登出功能
註冊認證中介軟體就一行代碼
app.UseAuthentication();
這裡關於認證中介軟體得說明一下,之前在1.0的時候提供了很多認證的中介軟體,什麼Facebook啊,Google啊,這些中間價將全部棄用,統一使用上面的代碼去註冊身份認證中介軟體,具體的認證策略在服務中指定,比如下面的代碼AddCookie()方法就指定了使用Cookie認證服務。
public void ConfigureServices(IServiceCollection services){ services.AddAuthentication(options => { options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme; }).AddCookie(options => { options.Cookie.Domain = ".domain.dev"; options.Cookie.Name = "sso"; options.Cookie.Path = "/"; options.DataProtectionProvider = DataProtectionProvider.Create(new DirectoryInfo(@"c:\shared-auth-ticket-keys\")); }); services.AddMvc();}
需要說明的是DataProtectionProvider屬性提供資料保護,會在指定的目錄下產生一個xml檔案用裡面的key去加密cookie。然後在頁面上放一個登陸按鈕
@if (Context.User.Identity.IsAuthenticated){ @Context.User.Identity.Name <a href="@Url.Action("SignOut")">登出</a>}else{ <a class="btn btn-default" href="http://passport.domain.dev/login?returnUrl=http://domain.dev">登入</a>}
OK,Portal項目就完成了。
所有的登陸請求http://passport.domain.dev/login?returnUrl=後面跟上調回的地址,在passport項目的登陸頁面放一個登陸按鈕(使用者名稱,密碼就省了,直接登陸)
<a class="btn btn-default" href="@Url.Action("SignIn","Login",new { returnUrl=Context.Request.Query["returnUrl"]})">登入</a>
public async Task<IActionResult> SignIn(string returnUrl){ var user = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, "bob") }, CookieAuthenticationDefaults.AuthenticationScheme)); await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, user, new AuthenticationProperties { IsPersistent = true, ExpiresUtc = DateTimeOffset.Now.Add(TimeSpan.FromDays(180)), }); if (string.IsNullOrWhiteSpace(returnUrl)) { returnUrl = "http://domain.dev"; } return Redirect(returnUrl);}
Passport項目的Configure和ConfigureServices方法跟Porta項目保持一樣。OK,Passport項目完事了
最後就剩Order項目了,剛才也說了Order項目肯定是不能匿名訪問的,這裡需要特殊設定一下
public void ConfigureServices(IServiceCollection services){ services.AddAuthentication(options => { options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme; }).AddCookie(options => { options.Cookie.Domain = ".domain.dev"; options.Cookie.Name = "sso"; options.Cookie.Path = "/"; options.LoginPath = "/login"; options.DataProtectionProvider = DataProtectionProvider.Create(new DirectoryInfo(@"c:\shared-auth-ticket-keys\")); }); // 不允許匿名訪問 services.AddMvc(options => { var policy = new AuthorizationPolicyBuilder() .RequireAuthenticatedUser() .Build(); options.Filters.Add(new AuthorizeFilter(policy)); });}
說一下LoginPath屬性,就是說當使用者沒有登陸的時候就會跳轉到LoginPath,但是LoginPath只能設定本地路徑,不能按照下面的方式
options.LoginPath = "http://passport.domain.dev/login"; // 這樣是錯誤的
所以我們上面設定的是/login
public class LoginController : Controller{ [AllowAnonymous] public IActionResult Index(string returnUrl) { return Redirect(string.Concat("http://passport.domain.dev/login?returnUrl=http://order.domain.dev", returnUrl)); }}
這樣我們就解決了跳轉的問題
好了 ,三個項目的代碼都寫完了,接下來將這三個項目不熟到IIS裡去
這裡又得說明一下必須將項目發布以後才能部署到IIS,不能直接指定項目的實體路徑,發到檔案系統預設的路徑應該是bin\Release\PublishOutput,應該指定這個路徑
建議大家在本地開發的時候盡量合理的使用網域名稱尾碼
代碼地址:https://github.com/bidianqing/SSO.Core.Sample
NET Core 2.0使用Cookie認證實現SSO單點登入