NET Core 2.0使用Cookie認證實現SSO單點登錄
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單點登錄