【问题标题】:Consuming secure ASP Net 5 web api using local account使用本地帐户使用安全的 ASP Net 5 web api
【发布时间】:2016-03-23 05:49:47
【问题描述】:

我需要使用本地帐户从 Web 客户端使用 ASP.NET 5 安全 Web API。过去有一个处理程序发行不记名令牌以支持 OAuth,现在不记名令牌发行责任已从身份中删除。有些人建议使用需要客户端注册的identityServer3,这与identity2 方法不同。在 ASP.NET 5 Web API 中实现授权的最简单方法是什么?在使用资源所有者密码流时,如何避免传递客户端 ID 和客户端密码以获取访问令牌?如何调用api避免传递范围?

【问题讨论】:

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


    【解决方案1】:

    我从this 构建了一个简单的不记名令牌颁发者,但使用身份密码哈希。您可以在下面看到完整的代码:

    public class TokenController : Controller
    {
        private readonly IBearerTokenGenerator generator;
        private readonly IClientsManager clientsManager;
        private readonly IOptions<TokenAuthOptions> options;
    
        public TokenController(IBearerTokenGenerator generator,
            IClientsManager clientsManager,
            IOptions<TokenAuthOptions> options)
        {
            this.generator = generator;
            this.clientsManager = clientsManager;
            this.options = options;
        }
    
        [HttpPost, AllowAnonymous]
        public IActionResult Post(AuthenticationViewModel req)
        {
            return clientsManager
                .Find(req.client_id, req.client_secret)
                .Map(c => c.Client)
                .Map(c => (IActionResult)new ObjectResult(new {
                    access_token = generator.Generate(c),
                    expires_in = options.Value.ExpirationDelay.TotalSeconds,
                    token_type = "Bearer"
                }))
                .ValueOrDefault(HttpUnauthorized);
        }
    }
    
    public class BearerTokenGenerator : IBearerTokenGenerator
    {
        private readonly IOptions<TokenAuthOptions> tokenOptions;
    
        public BearerTokenGenerator(IOptions<TokenAuthOptions> tokenOptions)
        {
            this.tokenOptions = tokenOptions;
        }
    
        public string Generate(Client client)
        {
            var expires = Clock.UtcNow.Add(tokenOptions.Value.ExpirationDelay);
            var handler = new JwtSecurityTokenHandler();
    
            var identity = new ClaimsIdentity(new GenericIdentity(client.Identifier, "TokenAuth"), new Claim[] {
                new Claim("client_id", client.Identifier)
            });
    
            var securityToken = handler.CreateToken(
                issuer: tokenOptions.Value.Issuer,
                audience: tokenOptions.Value.Audience,
                signingCredentials: tokenOptions.Value.SigningCredentials,
                subject: identity,
                expires: expires);
    
            return handler.WriteToken(securityToken);
        }
    }
    
    public class ClientsManager : IClientsManager
    {
        private readonly MembershipDataContext db;
        private readonly ISecretHasher hasher;
    
        public ClientsManager(MembershipDataContext db,
            ISecretHasher hasher)
        {
            this.db = db;
            this.hasher = hasher;
        }
    
        public void Create(string name, string identifier, string secret, Company company)
        {
            var client = new Client(name, identifier, company);
            db.Clients.Add(client);
    
            var hash = hasher.HashSecret(secret);
            var apiClient = new ApiClient(client, hash);
    
            db.ApiClients.Add(apiClient);
        }
    
        public Option<ApiClient> Find(string identifier, string secret)
        {
            return FindByIdentifier(identifier)
                .Where(c => hasher.Verify(c.SecretHash, secret));
        }
    
        public void ChangeSecret(string identifier, string secret)
        {
            var client = FindByIdentifier(identifier).ValueOrDefault(() => {
                throw new ArgumentException($"could not find any client with identifier { identifier }");
            });
    
            var hash = hasher.HashSecret(secret);
            client.ChangeSecret(hash);
        }
    
        public string GenerateRandomSecret()
        {
            const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
            var random = new Random();
            var generated = new string(Enumerable.Repeat(chars, 12).Select(s => s[random.Next(s.Length)]).ToArray());
            return Convert.ToBase64String(Encoding.UTF8.GetBytes(generated));
        }
    
        private Option<ApiClient> FindByIdentifier(string identifier)
        {
            return db.ApiClients
                .Include(c => c.Client)
                .SingleOrDefault(c => c.Client.Identifier == identifier)
                .ToOptionByRef();
        }
    }
    
    public class SecretHasher : ISecretHasher
    {
        private static Company fakeCompany = new Company("fake", "fake");
        private static Client fakeClient = new Client("fake", "fake", fakeCompany);
    
        private readonly IPasswordHasher<Client> hasher;
    
        public SecretHasher(IPasswordHasher<Client> hasher)
        {
            this.hasher = hasher;
        }
    
        public string HashSecret(string secret)
        {
            return hasher.HashPassword(fakeClient, secret);
        }
    
        public bool Verify(string hashed, string secret)
        {
            return hasher.VerifyHashedPassword(fakeClient, hashed, secret) == PasswordVerificationResult.Success;
        }
    }
    

    现在在 Startup.cs 中

                services.Configure<TokenAuthOptions>(options =>
            {
                options.Audience = "API";
                options.Issuer = "Web-App";
                options.SigningCredentials = new SigningCredentials(GetSigninKey(), SecurityAlgorithms.RsaSha256Signature);
                options.ExpirationDelay = TimeSpan.FromDays(365);
            });
    
                services.AddAuthorization(auth =>
            {
                auth.AddPolicy("Bearer", new AuthorizationPolicyBuilder()
                    .AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme‌​)
                    .RequireAuthenticatedUser()
                    .Build());
            }
    
            app.UseJwtBearerAuthentication(options =>
            {
                options.TokenValidationParameters.IssuerSigningKey = GetSigninKey();
                options.TokenValidationParameters.ValidAudience = "API";
                options.TokenValidationParameters.ValidIssuer = "Web-App";
                options.TokenValidationParameters.ValidateSignature = true;
                options.TokenValidationParameters.ValidateLifetime = true;
                options.TokenValidationParameters.ClockSkew = TimeSpan.FromMinutes(0);
            });
    

    【讨论】:

      猜你喜欢
      • 2023-03-11
      • 2016-06-04
      • 1970-01-01
      • 2014-12-10
      • 2013-11-10
      • 2015-06-14
      • 2021-05-12
      • 2023-03-28
      • 2015-04-16
      相关资源
      最近更新 更多