如何让ASP.NET使用Owin OpenId Connect库创建经过身份验证的会话?

时间:2017-02-20 22:08:33

标签: c# asp.net authentication owin openid-connect

在网上搜索了大量的例子后,我正在努力解决看似简单的问题。

我正在尝试扩展现在使用表单身份验证的现有ASP.NET应用程序,以便它可以使用OpenID Connect进行身份验证以及来自身份提供程序的一些角色信息。特别是我正在与我无法控制的现有托管身份提供程序集成。

我正在使用ASP.NET MVC和OpenIdConnect的Owin组件。即,

Microsoft.Owin.Security
Microsoft.Owin.Security.Cookies
Microsoft.Owin.Security.OpenIdConnect

我成功地能够:

  1. 在Web浏览器中 - 导航到使用[Authorize]属性
  2. 保护的控制器方法
  3. Owin组件正确地将我重定向到我可以进行身份​​验证的身份提供商,然后我被重定向回我的应用程序(注意:我的身份提供商要求传入redirect_uri,所以我目前将其设置为OpenIdConnectAuthenticationOptions启动配置的一部分。)
  4. 当重定向回到我的应用程序时,我能够看到access_token和id_token作为查询字符串的一部分。此外,我已经能够使用access_token调用用户信息端点并正确地使用该令牌导出有关用户的信息。
  5. 到目前为止一切顺利!但是。

    我没有掌握的内容以及我见过的大多数Owin示例似乎都没有解释:如果需要额外的配置,需要额外的配置才能让ASP.NET在我的应用程序中实际创建一个经过身份验证的会话从身份提供商重定向到我的应用程序。

    我从文档中得到的一般感觉是我不应该在Owin库中进行额外配置 - 一旦我将系统配置为使用cookie身份验证和OpenId Connect库 - 它应该只是工作。但是,这似乎并不像看起来那么容易。我猜我错过了什么。

    一些具体的考虑/观察:

    1. 我发现的许多示例都不需要在OpenIdConnectAuthenticationOptions中设置RedirectUri,但我的Identity Provider要求每次都设置此参数。
    2. 我发现的很少的例子解释了由于RedirectUri被击中而触发的控制器方法是应该用[授权]保护还是保持匿名。在我的测试中,如果我将其标记为[Authorize],我将进入无限重定向循环。如果我保持匿名,我可以在请求信息中看到令牌,但从未创建ASP.NET会话。例如,Request.IsAuthenticated始终为false。
    3. 作为测试,我在几个OpenIdConnectAuthenticationNotifications()事件中设置了断点,目前我只看到我的代码进入RedirectToIdentityProvider事件,而其他人似乎没有 - 这让我相信我我没有正确配置。
    4. 根据我发现的建议,我已经在web.config中以这种方式设置了身份验证节点,但如果我排除此节点,它似乎没有什么区别。

      <system.web>
          <authentication mode="None" />
      </system.web>
      
    5. 总结:

      1. 我是否需要专门编写代码来处理从Identity Provider返回的重定向,以便为给定用户手动设置ASP.NET Session(cookie等)?和
      2. 如果是这样,此代码是否应该由于RedirectUri被命中而被调用的控制器方法,或者代码是否应该进入OpenIdConnectAuthenticationNotifications()中可用的“通知”事件之一?
      3. 最后,如果我不应该在从身份提供商重定向后手动设置Authenticated会话(如果它应该自动工作),那么对此配置常见错误的任何建议?

        为了完整性:

        My Owin管道启动配置方法:

        public void Configuration(IAppBuilder app)
        {
            app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
        
            app.UseCookieAuthentication(new CookieAuthenticationOptions());
        
            app.UseOpenIdConnectAuthentication(
                new OpenIdConnectAuthenticationOptions
                {
                    //no problems on these as far as I can tell
                    ClientId = "client_id_string",
                    ClientSecret = "client_secret_string",
                    Authority = "url_to_identity_provider",
                    Scope = "email name etc",
        
                    //I'm properly redirected to this URL but not sure 
                    //if I should need to create the session manually
                    RedirectUri = "http://mymachine/mymvcapp/authorize",
        
                    //this causes the redirection to come with the access_token, 
                    //which is valid
                    ResponseType = "token",
                    SignInAsAuthenticationType = "Cookies",
                    Notifications = new OpenIdConnectAuthenticationNotifications()
                    {
                        RedirectToIdentityProvider = (context) =>
                        {
                            //I'm able to break into this method
                            return Task.FromResult(0);
                        },
                        MessageReceived = (context) =>
                        {
                            //doesn't seem to run this line
                            return Task.FromResult(0);
                        },
                        SecurityTokenReceived = (context) =>
                        {
                            //doesn't seem to run this line
                            return Task.FromResult(0);
                        },
                        SecurityTokenValidated = (context) =>
                        {
                            //doesn't seem to run this line
                            return Task.FromResult(0);
                        },
                        AuthorizationCodeReceived = (context) =>
                        {
                            //doesn't seem to run this line
                            return Task.FromResult(0);
                        },
                        AuthenticationFailed = (context) =>
                        {
                            //doesn't seem to run this line
                            return Task.FromResult(0);
                        },
                    },
                });
        }
        

        我正确启动登录流程的安全方法:

        [Authorize]
        public class HomeController : Controller
        {
            //I'm sent to the login flow the first time this is hit
            public ActionResult Index()
            {
                return View();
            }
        }
        

        我在RedirectUri上的方法被调用但确实表明已经创建了ASP.NET身份验证会话:

        public class AuthorizeController : Controller
        {
            // [Authorize] -- currently this Authorize attribute is turned off 
            //so the method is anonymous. 
        
            //If I turn that back on, I get infininte redirect loops to 
            //the Identity Provider
            public ActionResult Index()
            {
                //the incoming request to this controller method from the 
                //identity provider DOES include valid access_token and id_token 
                //(which can be used against the user info endpoint) but does not 
                //create a valid ASP.NET session for my web app
        
                //Request.IsAuthenticated is always false
        
                //should there be a manual creation of the ASP.NET 
                //session/cookie information in this controller method?
        
                //note: to me it would make most sense if this attribute was not
                //anonymous since it's unlikely that the Request would ever appear
                //as IsAuthenticated == true, but if you read the entire question
                //it will be clear why I'm trying this method with anonymous access
        
                return View();
            }
        }
        

1 个答案:

答案 0 :(得分:1)

正如您所发现的那样,您不能在外部服务器用于通知您用户被授权的方法上放置[Authorize]属性 - 会话尚未获得授权,您只是被告知它< em>应该。

幸运的是,创建该会话并不困难: How can I manually create a authentication cookie instead of the default method?

(我很确定你必须自己使用基本的Microsoft Owin做的事情 - 如果你愿意,你总是可以自己做。)