将用户设置为从WebAPI自定义中间件进行身份验证

时间:2017-02-10 06:42:44

标签: c# asp.net-web-api oauth-2.0 asp.net-identity

我正在学习在WebApi中实现新的自定义中间件(外部登录)来验证用户。我使用空模板来了解实际情况。

我收到了一些好文章和外部登录自定义中间件提供商链接,以帮助我实现这一目标。

  1. http://bitoftech.net/2014/08/11/asp-net-web-api-2-external-logins-social-logins-facebook-google-angularjs-app/
  2. https://www.simple-talk.com/dotnet/net-framework/creating-custom-oauth-middleware-for-mvc-5/
  3. https://github.com/TerribleDev/OwinOAuthProviders
  4. https://katanaproject.codeplex.com/SourceControl/latest#README
  5. 基于这些文章,我为Github完成了自定义中间件,并成功验证了用户。

    现在,我需要了解webapi身份系统如何对用户进行身份验证以及如何为此保存外部声明。因此,在成功从第三方登录后,我刚刚创建了声明并调用了SignIn方法。

    直到这一切都正常工作。

    但在此之后我尝试使用访问令牌(外部访问令牌)访问任何受保护资源,我只获得了未经授权。我假设因为我没有将用户注册到本地数据库,所以我可以使用相同的外部访问令牌来使用该资源。

    我试过两种方法。首先,在ExternalLogin方法本身中,我在登录后重定向到受保护资源。接下来我尝试了rest-client。

    我的身份验证配置代码:

    [assembly: OwinStartup(typeof(CustomExternalLogin.Startup))]
    namespace CustomExternalLogin
    {
        public class Startup
        {
            public void Configuration(IAppBuilder app)
            {
                // Enable the application to use a cookie to store information for the signed in user
                // and to use a cookie to temporarily store information about a user logging in with a third party login provider
                app.UseCookieAuthentication(new CookieAuthenticationOptions());
                app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
    
                //Use Git authentication
                app.UseGitAuthentication("myclientid", "myclientsecret");
            }
        }
    }
    

    我的控制器代码

        [Authorize]
        [RoutePrefix("api/Account")]
        public class AccountController : ApiController
        {
            [OverrideAuthorization]
            [HostAuthentication(DefaultAuthenticationTypes.ExternalCookie)]
            [AllowAnonymous]
            [Route("ExternalLogin", Name ="ExternalLogin")]
            public async Task<IHttpActionResult> GetExternalLogin(string provider, string error = null)
            {
                string redirectUri = string.Empty;
    
                //Check any error and return
                if(error != null)
                {
                    return BadRequest(Uri.EscapeDataString(error));
                }
    
                //if not current user is authenticated return challengeresult so that middleware continue for external authentication
    
                if (!User.Identity.IsAuthenticated)
                {
                    return new ChallengeResult(provider, this);
                }
    
                ClaimsIdentity externalIdentity = User.Identity as ClaimsIdentity;
                Claim providerClaim = externalIdentity.FindFirst(ClaimTypes.NameIdentifier);
                Claim userClaim = externalIdentity.FindFirst(ClaimTypes.Name);
    
                string token = externalIdentity.FindFirstValue("ExternalAccessToken");
                IEnumerable<Claim> claims = new List<Claim>
                {
                    new Claim(ClaimTypes.NameIdentifier, providerClaim.Value, null, providerClaim.Issuer),
                    new Claim(ClaimTypes.Name, userClaim.Value, null, userClaim.Issuer)
    
                };
    
                ClaimsIdentity identity = new ClaimsIdentity(claims, OAuthDefaults.AuthenticationType);
                Authentication.SignIn(identity);
    
                Uri currentUri = Request.RequestUri;
                string home = currentUri.Scheme + Uri.SchemeDelimiter + currentUri.Authority + currentUri.Segments[0] + currentUri.Segments[1] + "Home/User?access_token=Bearer " + token  ;
                return Redirect(home);
            }
    
            #region Helpers
            private IAuthenticationManager Authentication
            {
                get { return Request.GetOwinContext().Authentication; }
            }
            #endregion
        }
    }
    

    我的受保护资源代码:

    [Authorize]
    [Route("User", Name ="User")]
    public string GetUser()
    {
        var authentication = Request.GetOwinContext().Authentication;
    
        return "Welcome " + User.Identity.Name;
    }
    

    请帮我找到我错过的地方

    修改1:

    我收到了当前的问题。我试图使用外部令牌访问。 WebAPI授权使用本地验证令牌,因此始终失败。所以解决方案是创建本地访问令牌,我就完成了。工作正常。

    但目前我正在检查为什么Authentication.Signin()方法没有为我创建令牌?

1 个答案:

答案 0 :(得分:0)

最后我明白了。从我的编辑中,我们可以理解需要本地令牌来验证用户。为此,我们可以使用Authentication.Signin()方法。

选项1:使用Authentication.Signin()

此处的要点是此身份验证使用cookie来保存信息和承载令牌以对用户进行身份验证。所以我们需要在auth config

中包含以下几行
public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }


    OAuthOptions = new OAuthAuthorizationServerOptions
    {
        Provider = new ApplicationOAuthProvider(PublicClientId),
        AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
        AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
        // In production mode set AllowInsecureHttp = false
        AllowInsecureHttp = true
    };


    // Enable the application to use bearer tokens to authenticate users
    app.UseOAuthBearerTokens(OAuthOptions);

现在成功生成令牌并进行身份验证。这种方法的缺点是,它总是返回令牌和url。对于纯api开发更好地返回json等。

选项2:生成本地令牌并作为对象返回

这里我们可以简单地创建一个本地令牌并像我们想要的那样返回对象。为此,我们可以使用OAuthBearerAuthenticationOptions。

需要在auth config

中添加以下代码
public static OAuthBearerAuthenticationOptions OAuthBearerOptions { get; private set; }

    OAuthBearerOptions = new OAuthBearerAuthenticationOptions();

    app.UseOAuthBearerAuthentication(OAuthBearerOptions);

在此之后,我们可以创建一个帮助方法来创建本地令牌。已经解释了此方法,可以在以下文章步骤9中找到。

http://bitoftech.net/2014/08/11/asp-net-web-api-2-external-logins-social-logins-facebook-google-angularjs-app/

现在我很好。如果我的任何理解都错了,请解释