zoukankan      html  css  js  c++  java
  • 在ASP.NET中基于Owin OAuth使用Client Credentials Grant授权发放Token

    OAuth真是一个复杂的东东,即使你把OAuth规范倒背如流,在具体实现时也会无从下手。因此,Microsoft.Owin.Security.OAuth应运而生(它的实现代码在Katana项目中),帮助开发者偷了不少工,减了不少料。

    这篇博文试图通过一个简单的示例分享一下如何基于Microsoft.Owin.Security.OAuth,使用Client Credentials Grant授权方式给客户端发放access token。

    Client Credentials Grant的授权方式就是只验证客户端(Client),不验证用户(Resource Owner),只要客户端通过验证就发access token。举一个对应的应用场景例子,比如我们想提供一个“获取网站首页最新博文列表”的WebAPI给iOS App调用。由于这个数据与用户无关,所以不涉及用户登录与授权,不需要Resource Owner的参与。但我们不想任何人都可以调用这个WebAPI,所以要对客户端进行验证,而使用OAuth中的 Client Credentials Grant 授权方式可以很好地解决这个问题。

    具体实现方式如下:

    1)用Visual Studio 2013/2015创建一个Web API项目,VS会生成一堆OAuth相关代码。

    2)打开Startup.Auth.cs ,精简一下代码,我们只需要实现以Client Credentials Grant授权方式拿到token,其它无关代码全部清除,最终剩下如下代码:

    public partial class Startup
    {
        public void ConfigureAuth(IAppBuilder app)
        {
            var OAuthOptions = new OAuthAuthorizationServerOptions
            {
                TokenEndpointPath = new PathString("/token"),
                Provider = new CNBlogsAuthorizationServerProvider(),
                AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
                AllowInsecureHttp = true
            };
    
            app.UseOAuthBearerTokens(OAuthOptions);
        }
    }

    3)创建一个新的类 CNBlogsAuthorizationServerProvider,并继承自 OAuthAuthorizationServerProvider,重载 OAuthAuthorizationServerProvider() 与 GrantClientCredentials() 这两个方法。代码如下:

    public class CNBlogsAuthorizationServerProvider : OAuthAuthorizationServerProvider
    {
        public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
        {
            string clientId;
            string clientSecret;
            context.TryGetFormCredentials(out clientId, out clientSecret);
    
            if (clientId == "1234" && clientSecret == "5678")
            {
                context.Validated(clientId);
            }
    
            return base.ValidateClientAuthentication(context);
        }
    
        public override Task GrantClientCredentials(OAuthGrantClientCredentialsContext context)
        {
            var oAuthIdentity = new ClaimsIdentity(context.Options.AuthenticationType);
            oAuthIdentity.AddClaim(new Claim(ClaimTypes.Name, "iOS App"));
            var ticket = new AuthenticationTicket(oAuthIdentity, new AuthenticationProperties());
            context.Validated(ticket);
    
            return base.GrantClientCredentials(context);
        }
    }

    在 ValidateClientAuthentication() 方法中获取客户端的 client_id 与 client_secret 进行验证。

    在 GrantClientCredentials() 方法中对客户端进行授权,授了权就能发 access token 。

    这样,OAuth的服务端代码就完成了。这么简单?是的,就这么简单,因为有了Microsoft.Owin.Security.OAuth。

    4)然后写客户端调用代码测试一下:

    public class OAuthClientTest
    {
        private HttpClient _httpClient;
    
        public OAuthClientTest()
        {
            _httpClient = new HttpClient();
            _httpClient.BaseAddress = new Uri("http://openapi.cnblogs.com");
        }
    
        [Fact]
        public void Get_Accesss_Token_By_Client_Credentials_Grant()
        {
            var parameters = new Dictionary<string, string>();
            parameters.Add("client_id", "1234");
            parameters.Add("client_secret", "5678");
            parameters.Add("grant_type", "client_credentials");
    
            Console.WriteLine(_httpClient.PostAsync("/token", new FormUrlEncodedContent(parameters))
                .Result.Content.ReadAsStringAsync().Result);
        }
    }

    运行结果如下:

    {"access_token":"8PqaWilv_SJT7vRXambP7Mebyaf3KO1GXYHsqA-oPMOQF6xk1YpluczOZGo-WwATU5YmGb0wSR0cUQMC8RSZfwO8nwom7yG11FIANhy2PNiqTg2CYdJF0sf0ggFs6it_i3mc_m1iEFCK2dLBPDJXPI24wngCPR0wP_zugZvyKv314BM0PQmnnwg3kLXR1DISKRbs5-i59VCtFSZgkM7A0w","token_type":"bearer","expires_in":1209599}

    搞定!

    【更新】 

    建议使用Basic Authentication传递clientId与clientSecret,服务端CNBlogsAuthorizationServerProvider中的TryGetFormCredentials()改为TryGetBasicCredentials(),客户端的调用代码如下:

    public class OAuthClientTest
    {
        private HttpClient _httpClient;
    
        public OAuthClientTest()
        {
            _httpClient = new HttpClient();
            _httpClient.BaseAddress = new Uri("http://openapi.cnblogs.com");
        }
    
        [Fact]
        public void Get_Accesss_Token_By_Client_Credentials_Grant()
        {
            var clientId =  "1234";
            var clientSecret = "5678";        
            _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
                    "Basic",
                    Convert.ToBase64String(Encoding.ASCII.GetBytes(clientId + ":" + clientSecret)));
                    
            var parameters = new Dictionary<string, string>();        
            parameters.Add("grant_type", "client_credentials");       
    
            Console.WriteLine(_httpClient.PostAsync("/token", new FormUrlEncodedContent(parameters))
                .Result.Content.ReadAsStringAsync().Result);
        }
    }

    【参考资料】

    ASP.Net MVC: Creating an OAuth client credentials grant type token endpoint 

  • 相关阅读:
    Java Web
    Tomcat学习笔记
    Java Web学习笔记(2)
    Java Web学习笔记(1)
    2017-2018-1 Java演绎法 小组会议及交互汇总
    【Alpha版本】冲刺阶段
    【Alpha版本】冲刺阶段
    【Alpha版本】冲刺阶段
    【Alpha版本】冲刺阶段
    【Alpha版本】冲刺阶段
  • 原文地址:https://www.cnblogs.com/dudu/p/4569857.html
Copyright © 2011-2022 走看看