Web Api Owin+Oauth2.0(ClientCredentials)+Jwt Token权限认证控制

OAuth简介

OAuth简单说就是一种授权的协议,只要授权方和被授权方遵守这个协议去写代码提供服务,那双方就是实现了OAuth模式。

 

OAuth 2.0 四种授权模式:

  • 授权码模式(authorization code)
  • 简化模式(implicit)
  • 密码模式(resource owner password credentials)
  • 客户端模式(client credentials)

下面的实列就是 客户端模式(client credentials)

Jwt 简介

JSON Web Token(JWT)是一个开放式标准(RFC 7519),它定义了一种紧凑且自包含的方式,用于在各方之间以JSON对象安全传输信息。这些信息可以通过数字签名进行验证和信任。可以使用秘密(使用HMAC算法)或使用RSA的公钥/私钥对对JWT进行签名。

实列讲解

如上图所示引入对应得Nuget包。

在项目中创建 Startup.cs 文件,添加如下代码:

    /// <summary>
    ///     Startup
    /// </summary>
    public class Startup
    {
        private readonly HttpConfiguration _httpConfig;

        /// <summary>
        ///     Initializes a new instance of the <see cref="Startup" /> class.
        /// </summary>
        public Startup()
        {
            _httpConfig = new HttpConfiguration();
        }

        /// <summary>
        ///     Configurations the specified application.
        /// </summary>
        /// <param name="app">The application.</param>
        public void Configuration(IAppBuilder app)
        {
            ConfigureOAuthTokenGeneration(app);
            ConfigureOAuthTokenConsumption(app);
        }
        //配置token生成
        private void ConfigureOAuthTokenGeneration(IAppBuilder app)
        {
            var oAuthServerOptions = new OAuthAuthorizationServerOptions
            {
                //TODO:For Dev enviroment only (on production should be AllowInsecureHttp = false)
                AllowInsecureHttp = true,
                TokenEndpointPath = new PathString("/oauth/token"),//获取token请求地址
                AccessTokenExpireTimeSpan = TimeSpan.FromDays(5),//token过期时间
                Provider = new SimpleOAuthProvider(),//token生成服务
                AccessTokenFormat = new SimpleJwtFormat()//token生成Jwt格式
            };
            app.UseOAuthAuthorizationServer(oAuthServerOptions);
            app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
        }
        //配置token使用
        private void ConfigureOAuthTokenConsumption(IAppBuilder app)
        {
            var issuer = ConfigurationManager.AppSettings["oauth:Issuer"];
            var audienceIds = ConfigurationManager.AppSettings["oauth:Audiences"];
            var audienceSecrets = ConfigurationManager.AppSettings["oauth:Secrets"];
            var allowedAudiences = audienceIds.Split(new[] {","}, StringSplitOptions.RemoveEmptyEntries);
            var base64Keys = audienceSecrets.Split(new[] {","}, StringSplitOptions.RemoveEmptyEntries);
            var keys = base64Keys.Select(s => TextEncodings.Base64Url.Decode(s)).ToList();
            app.UseJwtBearerAuthentication(new JwtBearerAuthenticationOptions
            {
                AuthenticationMode = AuthenticationMode.Active,
                AllowedAudiences = allowedAudiences,
                IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
                {
                    new SymmetricKeyIssuerSecurityTokenProvider(issuer, keys)
                },
                Provider = new SimpleOAuthBearerAuthenticationProvider("access_token")
            });
        }

        
    }

 

SimpleOAuthProvider示例代码:

 

public class SimpleOAuthProvider : OAuthAuthorizationServerProvider
    {
        public override  Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
        {
           
            string clientId;
            string clientSecret;
            if (!context.TryGetBasicCredentials(out clientId, out clientSecret))
                context.TryGetFormCredentials(out clientId, out clientSecret);
            var authDbContext = new ExternalInterfaceBaseDbContext();
            ICustomerRepository customerRepository = new CustomerRepository(authDbContext);
            if (context.ClientId == null)
            {
                context.SetError("invalid_client", "The client_id is not set.");
                return Task.FromResult<object>(null); 
            }
            var secretKey = customerRepository.GetSecretKey(clientId);
            if (secretKey==null)
            {
                context.SetError("invalid_client", $"Invalid client_id '{context.ClientId}'.");
                return Task.FromResult<object>(null);
            }
            if (clientSecret != secretKey)
            {
                context.SetError("invalid_client", "Invalid client_Secret.");
                return Task.FromResult<object>(null);
            }

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

        public override Task GrantClientCredentials(OAuthGrantClientCredentialsContext context)
        {
            context.OwinContext.Response.Headers["Access-Control-Allow-Origin"] = "*";
            var oAuthIdentity = new ClaimsIdentity(context.Options.AuthenticationType);
            oAuthIdentity.AddClaim(new Claim(ClaimTypes.Name, "External Interface"));
            var properties = new Dictionary<string, string> { { "audience", context.ClientId ?? string.Empty } };
            var authenticationProperties = new AuthenticationProperties(properties);
            var ticket = new AuthenticationTicket(oAuthIdentity, authenticationProperties);
            context.Validated(ticket);
            return base.GrantClientCredentials(context);
        }
    }

使用Oauth2.0 ClientCredentials 模式获取token,授予客户凭证 。注意:不同得模式重写。GrantResourceOwnerCredentials 内部可以调用外部服务,以进行对用户账户信息的验证。

SimpleJwtFormat 示例代码:

public class SimpleJwtFormat : ISecureDataFormat<AuthenticationTicket>
    {
        private const string AudiencePropertyKey = "audience";
        private readonly string _issuer;
        private readonly string _audienceSecrets;

        public SimpleJwtFormat()
        {
            _issuer = ConfigurationManager.AppSettings["oauth:Issuer"];
            _audienceSecrets = ConfigurationManager.AppSettings["oauth:Secrets"];
        }

        public string Protect(AuthenticationTicket data)
        {
            if (data == null)
                throw new ArgumentNullException(nameof(data));
            var properties = data.Properties;
            var propertityDictionary = properties.Dictionary;
            var audienceId = propertityDictionary.ContainsKey(AudiencePropertyKey)
                ? propertityDictionary[AudiencePropertyKey]
                : null;
            if (string.IsNullOrWhiteSpace(audienceId))
                throw new InvalidOperationException("AuthenticationTicket.Properties does not include audience.");
            if (properties.IssuedUtc == null)
                throw new InvalidOperationException("AuthenticationTicket.Properties does not include issued.");
            if (properties.ExpiresUtc == null)
                throw new InvalidOperationException("AuthenticationTicket.Properties does not include expires.");
            var issued = properties.IssuedUtc.Value.UtcDateTime;
            var expires = properties.ExpiresUtc.Value.UtcDateTime;
            //TODO:
            //var authDbContext = new InstrumentDbContext();
            //var audienceRepository = new AudienceRepository(authDbContext);
            //var audience = audienceRepository.Get(audienceId);
            var decodedSecret = TextEncodings.Base64Url.Decode(_audienceSecrets);
            var signingCredentials = new HmacSigningCredentials(decodedSecret);
            var token = new JwtSecurityToken(_issuer, audienceId, data.Identity.Claims, issued, expires,
                signingCredentials);
            var handler = new JwtSecurityTokenHandler();
            var jwt = handler.WriteToken(token);
            return jwt;
        }
    }

根据授权Id生成Jwt Token返回。

SimpleOAuthBearerAuthenticationProvider 示例代码:

public class SimpleOAuthBearerAuthenticationProvider : OAuthBearerAuthenticationProvider
    {
        private readonly string _accessTokenName;

        public SimpleOAuthBearerAuthenticationProvider(string accessTokenName)
        {
            _accessTokenName = accessTokenName;
        }

        public override Task RequestToken(OAuthRequestTokenContext context)
        {
            var token = context.Request.Query.Get(_accessTokenName);
            if (!string.IsNullOrEmpty(token))
                context.Token = token;
            return Task.FromResult<object>(null);
        }
    }

配置AccessToken使用。

到这里权限认证代码基本完成,最后就是在控制器或者方法上配置权限控制特性 [Authorize]。

    [Authorize]
    [RoutePrefix("api/areas")]
    public class AreaController : ApiController

这样Web Api Owin + Oauth2.0 + Jwt Token 的权限认证框架就已经搭好了。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
首先,我们需要安装 `Microsoft.AspNet.WebApi` 和 `Microsoft.Owin.Security.Jwt` NuGet 包。 接下来,我们需要在 `WebApiConfig.cs` 文件中配置 Web API 路由: ```csharp public static void Register(HttpConfiguration config) { // 配置路由 config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); // 配置 JWT 认证 ConfigureJwtAuth(config); } ``` 然后,我们需要在 `Web.config` 文件中配置 JWT 令牌的密钥和有效期: ```xml <appSettings> <add key="jwtSecret" value="my_secret_key" /> <add key="jwtExpireDays" value="7" /> </appSettings> ``` 接下来,我们需要创建一个 `JwtAuthManager` 类来管理 JWT 认证: ```csharp using System; using System.Collections.Generic; using System.IdentityModel.Tokens.Jwt; using System.Linq; using System.Security.Claims; using System.Text; using Microsoft.IdentityModel.Tokens; public class JwtAuthManager : IJwtAuthManager { private readonly string _jwtSecret; private readonly double _jwtExpireDays; public JwtAuthManager(string jwtSecret, double jwtExpireDays) { _jwtSecret = jwtSecret; _jwtExpireDays = jwtExpireDays; } public string GenerateToken(IEnumerable<Claim> claims) { var key = Encoding.ASCII.GetBytes(_jwtSecret); var jwtToken = new JwtSecurityToken( claims: claims, expires: DateTime.Now.AddDays(_jwtExpireDays), signingCredentials: new SigningCredentials( new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature) ); var token = new JwtSecurityTokenHandler().WriteToken(jwtToken); return token; } } ``` 然后,我们需要创建一个 `JwtAuthAttribute` 特性,用于在控制器或操作方法上应用 JWT 认证: ```csharp [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class JwtAuthAttribute : AuthorizeAttribute { public override void OnAuthorization(HttpActionContext actionContext) { try { var token = actionContext.Request.Headers.Authorization.Parameter; var jwtAuthManager = actionContext.ControllerContext.Configuration .DependencyResolver.GetService(typeof(IJwtAuthManager)) as IJwtAuthManager; var principal = jwtAuthManager.ValidateToken(token); Thread.CurrentPrincipal = principal; HttpContext.Current.User = principal; } catch (Exception) { actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized); return; } base.OnAuthorization(actionContext); } } ``` 最后,我们需要在 `ConfigureJwtAuth` 方法中注册依赖项并配置 JWT 认证: ```csharp private static void ConfigureJwtAuth(HttpConfiguration config) { var jwtSecret = ConfigurationManager.AppSettings["jwtSecret"]; var jwtExpireDays = double.Parse(ConfigurationManager.AppSettings["jwtExpireDays"]); var container = new UnityContainer(); container.RegisterType<IJwtAuthManager, JwtAuthManager>( new InjectionConstructor(jwtSecret, jwtExpireDays)); config.DependencyResolver = new UnityResolver(container); config.Filters.Add(new JwtAuthAttribute()); } ``` 现在,我们可以在控制器或操作方法上应用 `JwtAuth` 特性来启用 JWT 认证: ```csharp [RoutePrefix("api/products")] public class ProductsController : ApiController { [HttpGet] [Route("")] [JwtAuth] public IHttpActionResult Get() { // ... } [HttpGet] [Route("{id}")] [JwtAuth] public IHttpActionResult Get(int id) { // ... } [HttpPost] [Route("")] [JwtAuth] public IHttpActionResult Post([FromBody] Product product) { // ... } // ... } ``` 这样,我们就成功地基于 JWT 实现了 Token 签名认证

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

V-BOX

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值