1. 程式人生 > >NET Core 2.0使用Cookie認證實現SSO單點登錄

NET Core 2.0使用Cookie認證實現SSO單點登錄

訪問 mvc side mes all add set 1.0 png

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單點登錄