如何在Asp.net MVC中编写OAuth2 Web API客户端

19
我们开发了一组Web API(REST),这些API受到授权服务器的保护。授权服务器已经颁发了客户端ID和客户端密钥。这些可以用于获取访问令牌。有效的令牌可以在后续调用资源服务器(REST API)时使用。
我想编写一个基于Web的客户端(Asp.net MVC 5)来使用这些API。是否有NuGet包可供下载,以帮助我实现客户端OAuth2流程?是否有人能够指导我一个关于在Asp.net MVC中编写OAuth2流程的良好示例?
更新 我能够使用下面的代码块获取访问令牌,但我想要的是“客户端凭据”OAuth 2流程,其中我不必输入登录名和密码。我现在拥有的代码是:
public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.SetDefaultSignInAsAuthenticationType("ClientCookie");

        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationMode = AuthenticationMode.Active,
            AuthenticationType = "ClientCookie",
            CookieName = CookieAuthenticationDefaults.CookiePrefix + "ClientCookie",
            ExpireTimeSpan = TimeSpan.FromMinutes(5)
        });

        app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
        {
            AuthenticationMode = AuthenticationMode.Active,
            AuthenticationType = OpenIdConnectAuthenticationDefaults.AuthenticationType,                
            SignInAsAuthenticationType = app.GetDefaultSignInAsAuthenticationType(),
            ClientId = ConfigurationManager.AppSettings["AuthServer:ClientId"],
            ClientSecret = ConfigurationManager.AppSettings["AuthServer:ClientSecret"],
            RedirectUri = ConfigurationManager.AppSettings["AuthServer:RedirectUrl"],
            Configuration = new OpenIdConnectConfiguration
            {
                AuthorizationEndpoint = "https://identityserver.com/oauth2/authorize",
                TokenEndpoint = "https://identityserver.com/oauth2/token"                                        
            },

            //ResponseType = "client_credentials", // Doesn't work
            ResponseType = "token",

            Notifications = new OpenIdConnectAuthenticationNotifications
            {
                AuthenticationFailed = notification =>
                {
                    if (string.Equals(notification.ProtocolMessage.Error, "access_denied", StringComparison.Ordinal))
                    {
                        notification.HandleResponse();

                        notification.Response.Redirect("/");
                    }

                    return Task.FromResult<object>(null);
                },

                AuthorizationCodeReceived = async notification =>
                {
                    using (var client = new HttpClient())
                    {
                        //var configuration = await notification.Options.ConfigurationManager.GetConfigurationAsync(notification.Request.CallCancelled);
                        String tokenEndPoint = "https://identityserver.com/oauth2/token";

                        //var request = new HttpRequestMessage(HttpMethod.Post, configuration.TokenEndpoint);
                        var request = new HttpRequestMessage(HttpMethod.Post, tokenEndPoint);
                        request.Content = new FormUrlEncodedContent(new Dictionary<string, string> {
                            { OpenIdConnectParameterNames.ClientId, notification.Options.ClientId },
                            { OpenIdConnectParameterNames.ClientSecret, notification.Options.ClientSecret },
                            { OpenIdConnectParameterNames.Code, notification.ProtocolMessage.Code },
                            { OpenIdConnectParameterNames.GrantType, "authorization_code" },
                            { OpenIdConnectParameterNames.RedirectUri, notification.Options.RedirectUri }
                        });

                        var response = await client.SendAsync(request, notification.Request.CallCancelled);
                        response.EnsureSuccessStatusCode();

                        var payload = JObject.Parse(await response.Content.ReadAsStringAsync());

                        // Add the access token to the returned ClaimsIdentity to make it easier to retrieve.
                        notification.AuthenticationTicket.Identity.AddClaim(new Claim(
                            type: OpenIdConnectParameterNames.AccessToken,
                            value: payload.Value<string>(OpenIdConnectParameterNames.AccessToken)));
                    }
                }
            }
        });


    }
}
1个回答

35

为了支持客户端凭据授权类型,您最好直接使用HttpClient:

var request = new HttpRequestMessage(HttpMethod.Post, "http://server.com/token");
request.Content = new FormUrlEncodedContent(new Dictionary<string, string> {
    { "client_id", "your client_id" },
    { "client_secret", "your client_secret" },
    { "grant_type", "client_credentials" }
});

var response = await client.SendAsync(request);
response.EnsureSuccessStatusCode();

var payload = JObject.Parse(await response.Content.ReadAsStringAsync());
var token = payload.Value<string>("access_token");

对于交互式流程(例如授权码流程),有两种更好的方法:


我已经取得了一些进展,并能够从身份验证服务器返回令牌。但我的需求是“客户端凭据”流,其中我不需要输入任何登录名和密码。令牌应基于客户端ID和客户端密钥发行。不知何故我无法配置它。我已更新问题并附上了我的当前代码。 - TejSoft
1
很抱歉,这现在是一个不同的问题。尽管使用了不太准确的术语,您最初的问题表明您正在使用授权代码流:“这些可以用于获取授权密钥,进而可以用于获取访问令牌”。为Katana 3开发的OIDC中间件不支持像资源所有者密码凭据流或客户端凭据流这样的非交互式流。您将不得不直接使用HttpClientgrant_type=client_credentials。您使用哪个授权服务器? - Kévin Chalet
是的,当我开始实施它时,事情变得更加清晰了。我正在使用一个基于Java的身份验证服务器,称为WS02。如果Katana 3不能用于“客户端凭据”,您推荐使用哪个其他的NuGet包?有任何示例吗? - TejSoft
IdentityServer3 这太棒了,可以实现您需要的所有流程。 - Ian
Postman对于获取新访问令牌拥有更多参数:1)令牌名称 2)grant_type = client_credentials,authorization_code,implicit,password credentials 3)访问令牌URL 4)客户端ID 5)客户端密码 6)范围:read:org 7)客户端认证:在正文中发送客户端凭据,以Basic Auth Header形式发送。 - Kiquenet
我对一个最新的OAuth2客户端解决方案(如微型NuGet包)在.Net(核心)中很感兴趣。有人可以指点一下吗? - Falco Alexander

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接