使用本地帐户使用安全的 ASP Net 5 web api
Posted
技术标签:
【中文标题】使用本地帐户使用安全的 ASP Net 5 web api【英文标题】:Consuming secure ASP Net 5 web api using local account 【发布时间】:2016-03-23 05:49:47 【问题描述】:我需要使用本地帐户从 Web 客户端使用 ASP.NET 5 安全 Web API。过去有一个处理程序发行不记名令牌以支持 OAuth,现在不记名令牌发行责任已从身份中删除。有些人建议使用需要客户端注册的identityServer3,这与identity2 方法不同。在 ASP.NET 5 Web API 中实现授权的最简单方法是什么?在使用资源所有者密码流时,如何避免传递客户端 ID 和客户端密码以获取访问令牌?如何调用api避免传递范围?
【问题讨论】:
【参考方案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);
);
【讨论】:
以上是关于使用本地帐户使用安全的 ASP Net 5 web api的主要内容,如果未能解决你的问题,请参考以下文章