我被这种行为困扰了。基本上,当请求刷新令牌时,WebAPI会执行从数据中删除旧的refresh_token的逻辑,并且我没有在调试器中看到任何错误。但是,API返回带有" invalid_grant"的HTTP 400。作为错误。
Startup.cs
// OAuth Server configuration
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = false,
TokenEndpointPath = new PathString("/oauth2/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(1),
AccessTokenFormat = new AccessTokenJwtFormat(issuer),
RefreshTokenProvider = new SimpleRefreshTokenProvider(),
RefreshTokenFormat = new RefreshTokenJwtFormat(issuer),
Provider = new CustomOAuthProvider()
};
// OAuth 2.0 Bearer Access Token Generation
app.UseOAuthAuthorizationServer(OAuthServerOptions);
SimpleRefreshTokenProvider.cs
public class SimpleRefreshTokenProvider : IAuthenticationTokenProvider
{
public async Task CreateAsync(AuthenticationTokenCreateContext context)
{
var clientid = context.Ticket.Properties.Dictionary["as:client_id"];
if (string.IsNullOrEmpty(clientid))
{
return;
}
var refreshTokenId = Guid.NewGuid().ToString("n");
var refreshTokenLifeTime = context.OwinContext.Get<string>("as:clientRefreshTokenLifeTime");
var _repo = ClientDbProvider.GetInstance();
var token = new RefreshToken()
{
Id = ClientHelper.GetHash(refreshTokenId),
ClientId = clientid,
Subject = context.Ticket.Identity.Name,
IssuedUtc = DateTime.UtcNow,
ExpiresUtc = DateTime.UtcNow.AddMinutes(Convert.ToDouble(refreshTokenLifeTime))
};
context.Ticket.Properties.IssuedUtc = new DateTimeOffset(token.IssuedUtc);
context.Ticket.Properties.ExpiresUtc = new DateTimeOffset(token.ExpiresUtc);
context.Ticket.Properties.Dictionary.Add("refreshTokenId", refreshTokenId);
context.Ticket.Identity.AddClaim(new Claim(ClaimTypes.Role, "refreshToken"));
token.ProtectedTicket = context.SerializeTicket();
var result = await _repo.AddRefreshToken(token);
if (result)
{
context.SetToken(token.ProtectedTicket);
}
return;
}
public async Task ReceiveAsync(AuthenticationTokenReceiveContext context)
{
var allowedOrigin = context.OwinContext.Get<string>("as:clientAllowedOrigin");
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { allowedOrigin });
var _repo = ClientDbProvider.GetInstance();
string hashedTokenId = ClientHelper.GetHash(context.Token);
var refreshToken = await _repo.FindRefreshToken(hashedTokenId);
if (refreshToken != null)
{
//Get protectedTicket from refreshToken class
context.DeserializeTicket(refreshToken.ProtectedTicket);
var result = await _repo.RemoveRefreshToken(hashedTokenId);
}
}
public void Create(AuthenticationTokenCreateContext context)
{
throw new NotImplementedException();
}
public void Receive(AuthenticationTokenReceiveContext context)
{
throw new NotImplementedException();
}
}
RefreshTokenJwtFormat.cs
public class RefreshTokenJwtFormat : ISecureDataFormat<AuthenticationTicket>
{
private const string AudiencePropertyKey = "audience";
private readonly string _issuer = string.Empty;
public RefreshTokenJwtFormat(string issuer)
{
_issuer = issuer;
audStore = new AudiencesStore();
}
public string Protect(AuthenticationTicket data)
{
if (data == null)
{
throw new ArgumentNullException("data");
}
string audienceId = data.Properties.Dictionary.ContainsKey(AudiencePropertyKey) ? data.Properties.Dictionary[AudiencePropertyKey] : null;
if (string.IsNullOrWhiteSpace(audienceId)) throw new InvalidOperationException("AuthenticationTicket.Properties does not include audience");
var audience = GetAudience(audienceId);
string symmetricKeyAsBase64 = audience.Base64Secret;
var keyByteArray = TextEncodings.Base64Url.Decode(symmetricKeyAsBase64);
var signingCredentials = new SigningCredentials(
new InMemorySymmetricSecurityKey(keyByteArray),
SecurityAlgorithms.HmacSha256Signature,
SecurityAlgorithms.Sha256Digest);
var issued = data.Properties.IssuedUtc;
var expires = data.Properties.ExpiresUtc;
var payload = new JwtPayload(_issuer, audienceId, data.Identity.Claims, issued.Value.UtcDateTime, expires.Value.UtcDateTime);
if (data.Properties.Dictionary.ContainsKey("refreshTokenId"))
{
payload.Add("refreshTokenId", data.Properties.Dictionary["refreshTokenId"]);
}
var header = new JwtHeader(signingCredentials);
var token = new JwtSecurityToken(header, payload);
var handler = new JwtSecurityTokenHandler();
var jwt = handler.WriteToken(token);
return jwt;
}
public AuthenticationTicket Unprotect(string protectedText)
{
var handler = new JwtSecurityTokenHandler();
SecurityToken securityToken = handler.ReadToken(protectedText);
var audienceId = ((JwtSecurityToken)securityToken).Claims.First(x => x.Type == "aud").Value;
var audience = GetAudience(audienceId);
string symmetricKeyAsBase64 = audience.Base64Secret;
var keyByteArray = TextEncodings.Base64Url.Decode(symmetricKeyAsBase64);
var securityKey = new InMemorySymmetricSecurityKey(keyByteArray);
var validationParameters = new TokenValidationParameters()
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = securityKey,
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero,
ValidateAudience = true,
ValidAudience = audienceId,
ValidateIssuer = true,
ValidIssuer = _issuer
};
SecurityToken validatedToken;
ClaimsPrincipal principal = null;
try
{
principal = handler.ValidateToken(protectedText, validationParameters, out validatedToken);
}
catch(Exception ex)
{
return null;
}
return new AuthenticationTicket(principal.Identities.First(), new AuthenticationProperties());
}
private Models.Audience GetAudience(string audienceId)
{
var findAudTask = Task.Run(() => audStore.FindAudienceAsync(audienceId));
findAudTask.Wait();
var audience = findAudTask.Result;
return audience;
}
private AudiencesStore audStore;
}
答案 0 :(得分:2)
首先你需要 在CustomOAuthProvider中实现GrantRefreshToken(OAuthGrantRefreshTokenContext上下文)
之类的东西return new AuthenticationTicket(principal.Identities.First(), new AuthenticationProperties());
其次,您需要在RefreshTokenJwtFormat中更改方法Unprotect。
替换
return new AuthenticationTicket(principal.Identities.First(), new AuthenticationProperties
{
IssuedUtc = validatedToken.ValidFrom,
ExpiresUtc = validatedToken.ValidTo
});
与
import java.math.BigDecimal;
import java.util.Scanner;
public class LargestOfTwo {
private Scanner scanner;
private Number a;
private Number b;
public static void main(String args[]) throws Exception {
LargestOfTwo app = new LargestOfTwo();
app.start();
}
private void start() {
readInputs();
Number largest = compare(a, b);
System.out.print("Largest of the numbers is: " + largest);
}
private void readInputs() {
scanner = new Scanner(System.in);
System.out.println("Enter two numbers, and I will show you which one is largest\n");
a = readInput();
b = readInput();
}
private Number readInput() {
Double d = scanner.nextDouble();
if (d == Math.floor(d)) {
return d.intValue();
} else {
return d;
}
}
private Number compare(Number x, Number y) {
if (new BigDecimal(x.floatValue()).compareTo(new BigDecimal(y.floatValue())) > 0) {
return x;
} else {
return y;
}
}
}
答案 1 :(得分:1)
我有类似的(工作)代码。我不是这方面的专家,但我对我的代码进行了一些比较并注意到:
在receiveAsync中,我的代码以:
结尾$(document).ready(function( e ){
//Add an preventDefault on your event in order to not do the submit of the form.
e.preventDefault();
$("button").click(function(){
//Get all the data from your form
var data = $(form).serialize();
$.ajax({
type: 'POST',
//send the data with the ajax.
// You can retrieve it in your php through $_POST['name of form field']
data: data,
url: 'calcc.php',
success: function(data) {
$("p").text(data);
}
});
});
});
设置故障单并返回值。
对于createAsync,我的代码以:
结束context.SetTicket(context.Ticket);
return Task.FromResult<object>(null);
尽管如此,不知道这是否会有所帮助