找回密码
 立即注册

C# ASP.NET WebApi 实现 oauth2 授权服务接口

2024-11-26 16:09| 发布者: admin| 查看: 307| 评论: 0

摘要: grant_typeclient_credentials 客户端凭证password 密码模式 用于资源所有者密码凭据token 隐藏式 、 简化式 简化模式又称为隐式授权码模式,它是授权码模式的一个简化版本authorization_code 授权码 客户端凭证认证 ...
 
grant_type
  1. client_credentials 客户端凭证
  2. password 密码模式 用于资源所有者密码凭据
  3. token 隐藏式 、 简化式 简化模式又称为隐式授权码模式,它是授权码模式的一个简化版本
  4. authorization_code 授权码
   客户端凭证认证流程如下:

authorization_code 授权码 认证流程如下

  今天着重讲一下关于authorization_code 授权码认证的 C# WebApi 实现过程

  StartUp.cs  配置认证接口

   public void Configuration(IAppBuilder app)

   {

            HttpConfiguration configuration = new HttpConfiguration();

            WebApiConfig.Register(configuration);

            OAuthAuthorizationServerOptions options = new OAuthAuthorizationServerOptions()

            {

                AllowInsecureHttp = false,

                AuthenticationMode = AuthenticationMode.Active,

                AuthorizeEndpointPath = new PathString("/oauth2"),

                TokenEndpointPath = new PathString(value: "/access_token"),

                AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),

                Provider = new OpenAuthorizationServerProvider(),

                AuthorizationCodeProvider = new OpenAuthorizationCodeProvider(),

                RefreshTokenProvider = new OpenRefreshTokenProvider(),

            };

            configuration.Formatters.JsonFormatter.SerializerSettings = new Newtonsoft.Json.JsonSerializerSettings()

            {

                ContractResolver = new CamelCasePropertyNamesContractResolver(),

                DateFormatString = "yyyy-MM-dd HH:mm:ss" 

            };


            app.UseOAuthAuthorizationServer(options);

            app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());

            app.UseCors(CorsOptions.AllowAll);

            app.UseWebApi(configuration);

        }

    

OpenAuthorizationServerProvider   需要继承  OAuthAuthorizationServerProvider  实现如下

public class OpenAuthorizationServerProvider : OAuthAuthorizationServerProvider

    {

        public override Task ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context)

        {

            context.Validated(context.RedirectUri);

            return base.ValidateClientRedirectUri(context);

        }


        public override async Task ValidateAuthorizeRequest(OAuthValidateAuthorizeRequestContext context)

        {

            if (context.AuthorizeRequest.ClientId.StartsWith("appidstr"))

            {

                await Task.Run(() => { context.Validated();});

            }

            else

            {

                await Task.Run(() => { context.Rejected(); });

            }

        }

        public override async Task AuthorizeEndpoint(OAuthAuthorizeEndpointContext context)

        {

            var redirectUri = context.Request.Query["redirect_uri"];

            var clientId = context.Request.Query["client_id"];

            var identity = new ClaimsIdentity(new GenericIdentity(clientId,OAuthDefaults.AuthenticationType));

            var authorizeCodeContext = new AuthenticationTokenCreateContext(context.OwinContext,context.Options.AuthorizationCodeFormat,new AuthenticationTicket(identity,new AuthenticationProperties(new Dictionary<string, string>{{"client_id", clientId},{"redirect_uri", redirectUri}}){IssuedUtc = DateTimeOffset.UtcNow,ExpiresUtc = DateTimeOffset.UtcNow.Add(context.Options.AccessTokenExpireTimeSpan)}));

            await context.Options.AuthorizationCodeProvider.CreateAsync(authorizeCodeContext);

            context.Response.Redirect(redirectUri + "?code=" + Uri.EscapeDataString(authorizeCodeContext.Token));

            context.RequestCompleted();

        }


        public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)

        {

            string clientId, clientSecret;

            context.TryGetFormCredentials(out clientId, out clientSecret);

            if (!clientId.StartsWith("appidstr"))

            {

                context.SetError("invalid_client", "未授权的客户端");

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

            }

            context.Validated();

            return Task.FromResult<object>(null);

        }


        public override Task GrantClientCredentials(OAuthGrantClientCredentialsContext context)

        {

            return base.GrantClientCredentials(context);

        }

        public override Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)

        {

            ClaimsIdentity identity = new GenericIdentity(name: context.ClientId, type: OAuthDefaults.AuthenticationType);

            int userid = 13;

            string role = "管理员";

            string scope = "权限1,权限2";

            identity.AddClaim(new Claim("userid", userid.ToString()));

            identity.AddClaim(new Claim("role", role));

            identity.AddClaim(new Claim("scope", scope));

            context.Validated(identity);

            return base.GrantResourceOwnerCredentials(context);

        }

        public override async Task ValidateTokenRequest(OAuthValidateTokenRequestContext context)

        {

            if (context.TokenRequest.IsAuthorizationCodeGrantType)

            {

                await Task.Run(()=>{context.Validated();});

            }

            else

            {

                await Task.Run(()=>{context.Rejected();});

            }

        }

    }

    PostMan 提交参数 第一步获取 code  


   第二步,通过 code 换取接口调用凭证 access_token 

    

     至此,就完成了 授权码模式的oAuth2认证,当然 access_token 需要客户端保存,根据 expires_in 过期时间刷新,来维持资源访问会话授权。


路过

雷人

握手

鲜花

鸡蛋

QQ|Archiver|手机版|小黑屋|软件开发编程门户 ( 陇ICP备2024013992号-1|甘公网安备62090002000130号 )

GMT+8, 2025-1-18 09:49 , Processed in 0.025415 second(s), 16 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

返回顶部