c# – 使用本地帐户使用安全的ASP Net 5 web api

我需要使用本地帐户从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);
        });

相关文章

在要实现单例模式的类当中添加如下代码:实例化的时候:frmC...
1、如果制作圆角窗体,窗体先继承DOTNETBAR的:public parti...
根据网上资料,自己很粗略的实现了一个winform搜索提示,但是...
近期在做DSOFramer这个控件,打算自己弄一个自定义控件来封装...
今天玩了一把WMI,查询了一下电脑的硬件信息,感觉很多代码都...
最近在研究WinWordControl这个控件,因为上级要求在系统里,...