我需要使用本地帐户从Web客户端使用ASP.NET 5安全Web API.在过去,有一个处理程序发出持票令牌以支持OAuth,现在持票人令牌发行责任已从身份中删除.有些人建议使用identityServer3,它需要客户端注册,这与identity2方法不同.在ASP.NET 5 Web API中实现授权的最简单方法是什么?在使用资源所有者密码流时,如何避免传递客户端ID和客户端密钥以获取访问令牌?如何调用api避免通过范围?
解决方法
我已经从
this构建了一个简单的承载令牌发行者,但使用了身份密码hasher.您可以在下方看到完整代码:
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); });