Jul*_*era 6 c# asp.net authentication asp.net-web-api owin
我想知道如何阻止用户同时使用多个刷新令牌.让我解释:
问题是,如果另一个用户使用相同的凭据登录,则将为同一身份生成另一个刷新令牌.所以,我想要做的是:如果某人使用具有活动刷新令牌的某些凭据再次登录,而不是生成新的凭证,请替换现有的,或删除它并插入新的.因此,当访问令牌到期时,先前的用户将被断开,因为刷新令牌不再存在.
另外,我如何实现一些服务来销毁认证服务器中的刷新令牌?因此,用户可以调用它来断开他的帐户,而不仅仅是删除cookie并等到它过期.
这是我的代码:
Startup.cs:
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}"
);
app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/auth"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(1),
Provider = new OAuthProvider(),
RefreshTokenProvider = new RefreshTokenProvider()
});
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
app.UseWebApi(config);
}
}
Run Code Online (Sandbox Code Playgroud)
OAuthProvider.cs:
public class OAuthProvider : OAuthAuthorizationServerProvider
{
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
return Task.FromResult<object>(null);
}
public override Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
try
{
var account = AccountRepository.Instance.GetByUsername(context.UserName);
if (account != null && Global.VerifyHash(context.Password, account.Password))
{
var claimsIdentity = new ClaimsIdentity(context.Options.AuthenticationType);
claimsIdentity.AddClaim(new Claim(ClaimTypes.Name, account.Username));
claimsIdentity.AddClaim(new Claim("DriverId", account.DriverId.ToString()));
var newTicket = new AuthenticationTicket(claimsIdentity, null);
context.Validated(newTicket);
}
}
catch { }
return Task.FromResult<object>(null);
}
public override Task GrantRefreshToken(OAuthGrantRefreshTokenContext context)
{
context.Validated();
return Task.FromResult<object>(null);
}
}
Run Code Online (Sandbox Code Playgroud)
RefreshTokenProvider.cs:
public class RefreshTokenProvider : AuthenticationTokenProvider
{
public override Task CreateAsync(AuthenticationTokenCreateContext context)
{
var refreshToken = new TokenModel()
{
Subject = context.Ticket.Identity.Name,
Token = GenerateToken(),
IssuedUtc = DateTime.UtcNow,
ExpiresUtc = DateTime.UtcNow.AddMinutes(5)
};
context.Ticket.Properties.IssuedUtc = refreshToken.IssuedUtc;
context.Ticket.Properties.ExpiresUtc = refreshToken.ExpiresUtc;
refreshToken.Ticket = context.SerializeTicket();
try
{
TokenRepository.Instance.Insert(refreshToken);
context.SetToken(refreshToken.Token);
}
catch { }
return Task.FromResult<object>(null);
}
public override Task ReceiveAsync(AuthenticationTokenReceiveContext context)
{
try
{
var refreshToken = TokenRepository.Instance.Get(context.Token);
if (refreshToken != null)
{
if (TokenRepository.Instance.Delete(refreshToken))
{
context.DeserializeTicket(refreshToken.Ticket);
}
}
}
catch { }
return Task.FromResult<object>(null);
}
private string GenerateToken()
{
HashAlgorithm hashAlgorithm = new SHA256CryptoServiceProvider();
byte[] byteValue = Encoding.UTF8.GetBytes(Guid.NewGuid().ToString("N"));
byte[] byteHash = hashAlgorithm.ComputeHash(byteValue);
return Convert.ToBase64String(byteHash);
}
}
Run Code Online (Sandbox Code Playgroud)
还有一个问题:如何在catch中抛出内部服务器错误?因为它实际上正在返回invalid_grant,但是catch意味着数据库错误,而不是无效的凭据或令牌.
谢谢你的帮助,对不好的英语感到抱歉.我希望你明白!
小智 1
考虑以下:
您不必阻止用户。访问令牌很快就会过期,只需确保刷新令牌时不会颁发新的访问令牌即可。您可以通过检查刷新令牌来完成此操作。如果加密的刷新令牌与数据库中的加密刷新令牌不匹配,将返回“invalid_grant”。用户只有一个选择:重新登录。
如果用户使用凭据登录,刷新令牌就会更新(也在数据库中)。这将自动使“旧”刷新令牌失效。
您可以在 RefreshTokenProvider.CreateAsync 中实现第 2 点和第 3 点。一些伪代码:
// using Microsoft.AspNet.Identity;
public override Task CreateAsync(AuthenticationTokenCreateContext context)
{
var form = context.Request.ReadFormAsync().Result;
var grantType = form.GetValues("grant_type");
if (grantType[0] != "refresh_token")
{
// your code
...
// One day
int expire = 24 * 60 * 60;
context.Ticket.Properties.ExpiresUtc = new DateTimeOffset(DateTime.Now.AddSeconds(expire));
// Store the encrypted token in the database
var currentUser = context.Ticket.Identity.GetUserId();
TokenRepository.Instance.EncryptAndSaveTokenInDatabase(context.Token, currentUser);
}
base.Create(context);
}
Run Code Online (Sandbox Code Playgroud)
关于错误,直接返回即可invalid_grant。您预计数据库多久会失败一次?客户端将期望登录或接收“invalid_grant”。它知道如何处理(重定向到登录页面)。客户端不必知道存在数据库错误。如果您需要更多信息,可以在后台登录。
| 归档时间: |
|
| 查看次数: |
1360 次 |
| 最近记录: |