使用用户名和密码登录时,我会生成令牌。一切都很好。
现在,我正在尝试实施Facebook登录。然后生成令牌,但是当我尝试从[Authorized]
Api User.Identity.GetUserId<int>()
获取令牌时,我会返回0;
如果我通过/token
Api 登录,则一切正常,并且令牌更长。
用户已创建,一切正常。但是,无法在[Authorized] Apis中获得UserId,我通过AuthenticationProperties
中的Identity
传递了它。
这是我的OAuth类:
public static OAuthBearerAuthenticationOptions OAuthBearerOptions { get; private set; }
public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }
public static string PublicClientId { get; private set; }
public static void UseOAuthAuthentication(this IAppBuilder app) {
app.Use(async (context, next) => {
if (string.IsNullOrWhiteSpace(context.Request.Headers["Authorization"])) {
if (context.Request.QueryString.HasValue) {
var token = context.Request.QueryString.Value
.Split('&')
.SingleOrDefault(x => x.Contains("authorization"))?.Split('=')[1];
if (!string.IsNullOrWhiteSpace(token)) {
context.Request.Headers.Add("Authorization", new[] { $"Bearer {token}" });
}
}
}
await next.Invoke();
});
// Configure the db context and user manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a user logging in with a third party login provider
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// Configure the application for OAuth based flow
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions {
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
// In production mode set AllowInsecureHttp = false
AllowInsecureHttp = true
};
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);
OAuthBearerOptions = new OAuthBearerAuthenticationOptions();
OAuthBearerOptions.AccessTokenFormat = OAuthOptions.AccessTokenFormat;
OAuthBearerOptions.AccessTokenProvider = OAuthOptions.AccessTokenProvider;
OAuthBearerOptions.AuthenticationMode = OAuthOptions.AuthenticationMode;
OAuthBearerOptions.AuthenticationType = OAuthOptions.AuthenticationType;
OAuthBearerOptions.Description = OAuthOptions.Description;
// The provider is the only object we need to redefine. See below for the implementation
OAuthBearerOptions.Provider = new CustomBearerAuthenticationProvider();
OAuthBearerOptions.SystemClock = OAuthOptions.SystemClock;
app.UseOAuthBearerAuthentication(OAuthBearerOptions);
}
}
public class CustomBearerAuthenticationProvider : OAuthBearerAuthenticationProvider {
// This validates the identity based on the issuer of the claim.
// The issuer is set in the API endpoint that logs the user in
public override Task ValidateIdentity(OAuthValidateIdentityContext context) {
var claims = context.Ticket.Identity.Claims;
if (!claims.Any() || claims.Any(claim => claim.Type != "FacebookAccessToken")) // modify claim name
context.Rejected();
return Task.FromResult<object>(null);
}
}
这是我的Facebook登录课程:
if (!ModelState.IsValid) {
return BadRequest(ModelState);
}
if (string.IsNullOrEmpty(model.token)) {
return BadRequest("No access token");
}
var tokenExpirationTimeSpan = TimeSpan.FromDays(300);
ApplicationUser user = null;
string username;
// Get the fb access token and make a graph call to the /me endpoint
var fbUser = await VerifyFacebookAccessToken(model.token);
if (fbUser == null) {
return BadRequest("Invalid OAuth access token");
}
UserLoginInfo loginInfo = new UserLoginInfo("Facebook", model.username);
user = await UserManager.FindByNameAsync(fbUser.email);
// If user not found, register him with username.
if (user == null) {
if (String.IsNullOrEmpty(model.username))
return BadRequest("unregistered user");
user = new ApplicationUser { UserName = model.username };
var result = await UserManager.CreateAsync(user);
if (result.Succeeded) {
result = await UserManager.AddLoginAsync(user.Id, loginInfo);
username = model.username;
if (!result.Succeeded)
return BadRequest("cannot add facebook login");
}
else {
return BadRequest("cannot create user");
}
}
else {
// existed user.
username = user.UserName;
}
// common process: Facebook claims update, Login token generation
user = await UserManager.FindByNameAsync(username);
// Optional: make email address confirmed when user is logged in from Facebook.
user.Email = fbUser.email;
user.EmailConfirmed = true;
await UserManager.UpdateAsync(user);
// Sign-in the user using the OWIN flow
var identity = new ClaimsIdentity(OAuthAuthentication.OAuthOptions.AuthenticationType);
var claims = await UserManager.GetClaimsAsync(user.Id);
var newClaim = new Claim("FacebookAccessToken", model.token); // For compatibility with ASP.NET MVC AccountController
var oldClaim = claims.FirstOrDefault(c => c.Type.Equals("FacebookAccessToken"));
if (oldClaim == null) {
var claimResult = await UserManager.AddClaimAsync(user.Id, newClaim);
if (!claimResult.Succeeded)
return BadRequest("cannot add claims");
}
else {
await UserManager.RemoveClaimAsync(user.Id, oldClaim);
await UserManager.AddClaimAsync(user.Id, newClaim);
}
Dictionary<string, string> properties = new Dictionary<string, string>();
properties.Add("UserId", user.Id+"");
properties.Add("UserName", user.UserName+"");
properties.Add("Role", "user");
//AuthenticationProperties properties = ApplicationOAuthProvider.CreateProperties(user.UserName);
AuthenticationProperties authProperties = new AuthenticationProperties(properties);
var currentUtc = new Microsoft.Owin.Infrastructure.SystemClock().UtcNow;
authProperties.IssuedUtc = currentUtc;
authProperties.ExpiresUtc = currentUtc.Add(tokenExpirationTimeSpan);
AuthenticationTicket ticket = new AuthenticationTicket(identity, authProperties);
var accesstoken = OAuthAuthentication.OAuthOptions.AccessTokenFormat.Protect(ticket);
Request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accesstoken);
Authentication.SignIn(identity);
// Create the response building a JSON object that mimics exactly the one issued by the default /Token endpoint
JObject blob = new JObject(
new JProperty("userName", user.UserName),
new JProperty("access_token", accesstoken),
new JProperty("token_type", "bearer"),
new JProperty("expires_in", tokenExpirationTimeSpan.TotalSeconds.ToString()),
new JProperty(".issued", ticket.Properties.IssuedUtc.ToString()),
new JProperty(".expires", ticket.Properties.ExpiresUtc.ToString()),
new JProperty("model.token", model.token)
);
// Return OK
return Ok(blob);
我尝试通过以下方式生成AccessToken:
OAuthAuthentication.OAuthOptions.AccessTokenFormat.Protect(ticket);
和:
OAuthAuthentication.OAuthBearerOptions.AccessTokenFormat.Protect(ticket);
这是相同的...比我从/Token
api获得的令牌短。