C# 如何在asp.net web api中自定义oAuth令牌提供程序

C# 如何在asp.net web api中自定义oAuth令牌提供程序,c#,asp.net-web-api,oauth,asp.net-identity,access-token,C#,Asp.net Web Api,Oauth,Asp.net Identity,Access Token,我想改变默认的承载令牌系统的工作方式 我想登录到webAPI,提供设备的用户名、密码和mac地址。像这样 Content-Type: application/x-www-form-urlencoded username=test&password=P@ssword&grant_type=password&client_id=android&device_info=MAC_Address 然后我希望API为我提供一个刷新令牌。此令牌的有效期为7天,并允许我

我想改变默认的承载令牌系统的工作方式

我想登录到webAPI,提供设备的用户名、密码和mac地址。像这样

Content-Type: application/x-www-form-urlencoded    
username=test&password=P@ssword&grant_type=password&client_id=android&device_info=MAC_Address
然后我希望API为我提供一个刷新令牌。此令牌的有效期为7天,并允许我获取新的访问令牌。但是,在刷新令牌中,我希望在令牌中保存/嵌入用户密码的安全戳以及删除日期。这样,当请求新的访问令牌时,我可以检查安全戳。(解决密码更改方案)

我的访问令牌只需要存储少量信息就可以工作。我不要求访问令牌存储任何特定的内容。我希望它尽可能小。当它过期时,我将使用我的刷新令牌请求一个新的访问令牌

现在我已经试着去实现上面的内容,但是我自己对在哪里实现什么感到非常困惑。这是我得到的

步骤1:Startup.Auth.cs

//Configure the application for OAuth based flow
PublicClientId = "self";

OAuthOptions = new OAuthAuthorizationServerOptions
{
    AllowInsecureHttp = true,
    TokenEndpointPath = new PathString("/Token"),
    AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),

    Provider = new SimpleAuthorizationServerProvider(),
    RefreshTokenProvider = new SimpleRefreshTokenProvider(),           
    AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(20)
};
现在在这里我已经有一些问题了。我想要两个提供者,一个处理
刷新令牌
,另一个处理
访问令牌
。我需要设置哪些提供者?因为我看到还有一个叫做
AccessTokenProvider=
那么
Provider=
是做什么的

步骤2:重新设置TokenProvider。这就是我到目前为止所做的:

public class SimpleRefreshTokenProvider : IAuthenticationTokenProvider
    {
        //Used to store all the refresh tokens
        public static ConcurrentDictionary<string, AuthenticationTicket> RefreshTokens = new ConcurrentDictionary<string, AuthenticationTicket>();

        public Task CreateAsync(AuthenticationTokenCreateContext context)
        {
            var guid = Guid.NewGuid().ToString("N");

            //copy properties and set the desired lifetime of refresh token
            var refreshTokenProperties = new AuthenticationProperties(context.Ticket.Properties.Dictionary)
            {
                IssuedUtc = context.Ticket.Properties.IssuedUtc,
                ExpiresUtc = DateTime.UtcNow.AddDays(7)
            };

           //TODO: get mac address from the request headers??
           //TODO: save the mac address to db along with user and date       

            var refreshTokenTicket = new AuthenticationTicket(context.Ticket.Identity, refreshTokenProperties);
            RefreshTokens.TryAdd(guid, refreshTokenTicket);

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

        public Task ReceiveAsync(AuthenticationTokenReceiveContext context)
        {
            AuthenticationTicket ticket;

            if (RefreshTokens.TryRemove(context.Token, out ticket))
            {
                context.SetTicket(ticket);
            }
            return Task.FromResult<object>(null);
        }

        public void Receive(AuthenticationTokenReceiveContext context)
        {
            throw new NotImplementedException();
        }

        public void Create(AuthenticationTokenCreateContext context)
        {
            throw new NotImplementedException();
        }
    }
公共类SimpleRefreshTokenProvider:IAAuthenticationTokenProvider
{
//用于存储所有刷新令牌
公共静态ConcurrentDictionary RefreshTokens=新ConcurrentDictionary();
公共任务CreateSync(AuthenticationTokenCreateContext上下文)
{
var guid=guid.NewGuid().ToString(“N”);
//复制属性并设置刷新令牌的所需生存期
var refreshttokenproperties=newauthenticationproperties(context.Ticket.Properties.Dictionary)
{
IssuedUtc=context.Ticket.Properties.IssuedUtc,
ExpiresUtc=DateTime.UtcNow.AddDays(7)
};
//TODO:从请求头获取mac地址??
//TODO:将mac地址与用户和日期一起保存到db
var refreshttokenticket=newauthenticationticket(context.Ticket.Identity,refreshttokenproperties);
RefreshTokens.TryAdd(guid,refreshTokenTicket);
SetToken(guid);
返回Task.FromResult(空);
}
公共任务ReceiveAsync(AuthenticationTokenReceiveContext上下文)
{
认证票证;
if(refreshtokes.TryRemove(context.Token,out ticket))
{
上下文。设置票证(票证);
}
返回Task.FromResult(空);
}
public void Receive(AuthenticationTokenReceiveContext上下文)
{
抛出新的NotImplementedException();
}
公共void创建(AuthenticationTokenCreateContext上下文)
{
抛出新的NotImplementedException();
}
}
如果我理解正确的话。SimpleRefreshTokenProvider的目的是建立一个RefreshToken,并在api接收到一个包含RefreshToken的请求时验证它

步骤3:SimpleAuthorizationServerProvider。这就是我目前所拥有的。但我有一种感觉,这就是我出错的地方。或者我感到困惑,这门课的目的是什么?是否不验证AccessToken

 public class SimpleAuthorizationServerProvider : OAuthAuthorizationServerProvider
        {
            public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
            {
                // Not concerned about clients yet
                context.Validated();
            }        

            public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
            {
                // validate user credentials 
                var userManager = context.OwinContext.GetUserManager<FskUserManager>();
                FskUser user = await userManager.FindAsync(context.UserName, context.Password);
                if (user == null)
                {
                    context.SetError("invalid_grant", "The user name or password is incorrect.");
                    return;
                }          

                // create identity
                ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager,
                      OAuthDefaults.AuthenticationType);
                ClaimsIdentity cookiesIdentity = await user.GenerateUserIdentityAsync(userManager,
                    CookieAuthenticationDefaults.AuthenticationType);

                //Set properties of the token
                // create metadata to pass on to refresh token provider
                AuthenticationProperties properties = new AuthenticationProperties(new Dictionary<string, string>
                {
                    {"userName", user.UserName}               
                });

                AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
                context.Validated(ticket);
                context.Request.Context.Authentication.SignIn(cookiesIdentity);
            }       

            public override async Task GrantRefreshToken(OAuthGrantRefreshTokenContext context)
            {
                string originalClient;
                context.Ticket.Properties.Dictionary.TryGetValue("as:client_id", out originalClient);

                var currentClient = context.ClientId;           

                // chance to change authentication ticket for refresh token requests
                var newId = new ClaimsIdentity(context.Ticket.Identity);
                newId.AddClaim(new Claim("newClaim", "refreshToken"));

                var newTicket = new AuthenticationTicket(newId, context.Ticket.Properties);
                context.Validated(newTicket);
            }
        }
公共类SimpleAuthorizationServerProvider:OAuthAuthorizationServerProvider
{
公共重写异步任务ValidateClientAuthentication(OAuthValidateClientAuthenticationContext)
{
//还不关心客户吗
context.Validated();
}        
公共重写异步任务GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentials上下文)
{
//验证用户凭据
var userManager=context.OwinContext.GetUserManager();
FskUser user=await userManager.FindAsync(context.UserName,context.Password);
if(user==null)
{
SetError(“无效的授权”,“用户名或密码不正确”);
回来
}          
//创造身份
ClaimsIdentity oAuthIdentity=等待用户.GenerateUserIdentityAsync(userManager,
OAuthDefaults.AuthenticationType);
ClaimSideEntity cookiesIdentity=等待用户.GenerateUserIdentity异步(userManager,
CookieAuthenticationDefaults.AuthenticationType);
//设置令牌的属性
//创建要传递给刷新令牌提供程序的元数据
AuthenticationProperties=新的AuthenticationProperties(新字典
{
{“userName”,user.userName}
});
AuthenticationTicket=新的AuthenticationTicket(OAuthidentitity,属性);
上下文。已验证(票证);
context.Request.context.Authentication.sign(cookiesIdentity);
}       
公共重写异步任务GrantRefreshToken(OAuthGrantRefreshTokenContext)
{
字符串原始客户端;
context.Ticket.Properties.Dictionary.TryGetValue(“as:client_id”,out originalClient);
var currentClient=context.ClientId;
//更改刷新令牌请求的身份验证票证的机会
var newId=newclaimsidentity(context.Ticket.Identity);
newId.AddClaim(新索赔(“新索赔”、“刷新令牌”));
var newTicket=new