zoukankan      html  css  js  c++  java
  • 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,不能直接指定项目的物理路径,发到文件系统默认的路径应该是binReleasePublishOutput,应该指定这个路径

    建议大家在本地开发的时候尽量合理的使用域名后缀

    代码地址:https://github.com/bidianqing/SSO.Core.Sample

  • 相关阅读:
    Mina、Netty、Twisted一起学(八):HTTP服务器
    Mina、Netty、Twisted一起学(七):发布/订阅(Publish/Subscribe)
    梦想还是要有的,万一实现了呢(校招季)
    我的地盘听我的
    React源码剖析系列 - 生命周期的管理艺术
    实现搜索联想
    为你的简历加分
    twobin博客样式—“蓝白之风”
    一起学习jQuery2.0.3源码—1.开篇
    this的安身之处
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/7456704.html
Copyright © 2011-2022 走看看