我可能搞错了,但我一直在关注本文中的示例设置:使用 ASOS 创建您自己的 OpenID Connect 服务器,但是,它没有解释如何实现两个因素,因为这不是主要目的文章。
本文中唯一提到的两个派系是在令牌端点中,其中检查了两个因素身份验证,如果启用了两个因素,它会拒绝对令牌的请求。所以我在我的客户端应用程序中添加了一个检查,检查特定的拒绝条件,然后重定向到一个要求两个因素代码的页面。此页面首先调用授权端点,该端点将代码发送到存档的用户手机。然后,一旦用户输入了代码,它就会使用该代码再次调用授权端点,并且处理授权端点的方法会验证代码并在成功时返回 SignInResult。但是,我在返回 SignInResult 的 SignIn(principle, properties, schema) 方法中收到 500 错误。
首先,我想知道我是否做对了,其次,如果我做对了,我做错了什么?请在下面找到我的相关代码:
授权提供者:
public override async Task HandleTokenRequest(HandleTokenRequestContext context) {
var _dbContext = context.HttpContext.RequestServices.GetRequiredService<DbContext>();
if(context.Request.IsPasswordGrantType()) {
var u = await _dbContext.Users.Include(m => m.Organization).SingleOrDefaultAsync(x => x.Email.ToLowerInvariant() == context.Request.Username.ToLowerInvariant());
if(u == null || !PasswordHelper.VerifyPassword(context.Request.Password, u.Password)) {
context.Reject(
error: OpenIdConnectConstants.Errors.AccessDenied,
description: "The email or password is incorrect");
return;
} else if(u.Organization == null) {
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidGrant,
description: "Your user account is not associated with an organization.");
return;
}
// // Reject the token request if two-factor authentication has been enabled by the user.
if(u.TwoFactorEnabled) {
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidGrant,
description: "Two-factor authentication is required for this account.");
return;
}
var identity = new ClaimsIdentity(context.Options.AuthenticationScheme);
List<Claim> claims = new List<Claim>();
claims.Add(new Claim(ClaimTypes.NameIdentifier, u.Id.ToString()));
claims.Add(new Claim(ClaimTypes.Name, context.Request.Username));
claims.Add(new Claim(ClaimTypes.Role, u.RoleString));
claims.Add(new Claim("user_id", u.Id.ToString()));
claims.Add(new Claim("org_id", u.Organization.Id.ToString()));
foreach(var claim in claims) {
claim.SetDestinations(new List<string> { OpenIdConnectConstants.Destinations.AccessToken, OpenIdConnectConstants.Destinations.IdentityToken });
}
identity.AddClaims(claims);
var ticket = new AuthenticationTicket(
new ClaimsPrincipal(identity),
new AuthenticationProperties(),
context.Options.AuthenticationScheme);
// Set the list of scopes granted to the client application.
ticket.SetScopes(
/* openid: */ OpenIdConnectConstants.Scopes.OpenId,
/* email: */ OpenIdConnectConstants.Scopes.Email,
/* profile: */ OpenIdConnectConstants.Scopes.Profile,
/* offline_access: */ OpenIdConnectConstants.Scopes.OfflineAccess);
context.Validate(ticket);
}
}
授权方式:
[HttpPost]
[Route("authorize")]
public async Task<IActionResult> Authorize() {
var request = HttpContext.GetOpenIdConnectRequest();
if(request.Code == null) {
var u = await _dbContext.Users.SingleOrDefaultAsync(x => x.Email.ToLowerInvariant() == request.Username.ToLowerInvariant());
if(u == null || !PasswordHelper.VerifyPassword(request.Password, u.Password)) {
return Forbid(OpenIdConnectServerDefaults.AuthenticationScheme);
}
var response = await _twoFactorProvider.SendCode(CodeMethods.sms, u.AuthyId);
return Ok(new { Id = u.AuthyId, Response = response });
} else {
var response = await _twoFactorProvider.VerifyCode(request.Code, int.Parse(request.Username));
if(response.Token != "is valid") {
return Forbid(OpenIdConnectServerDefaults.AuthenticationScheme);
}
var u = await _dbContext.Users.Include(m => m.Organization).SingleOrDefaultAsync(x => x.AuthyId == int.Parse(request.Username));
var identity = new ClaimsIdentity(OpenIdConnectServerDefaults.AuthenticationScheme);
List<Claim> claims = new List<Claim>();
claims.Add(new Claim(ClaimTypes.NameIdentifier, u.Id.ToString()));
claims.Add(new Claim(ClaimTypes.Name, u.Email));
claims.Add(new Claim(ClaimTypes.Role, u.RoleString));
claims.Add(new Claim("user_id", u.Id.ToString()));
claims.Add(new Claim("org_id", u.Organization.Id.ToString()));
foreach(var claim in claims) {
claim.SetDestinations(new List<string> { OpenIdConnectConstants.Destinations.AccessToken, OpenIdConnectConstants.Destinations.IdentityToken });
}
identity.AddClaims(claims);
var ticket = new AuthenticationTicket(
new ClaimsPrincipal(identity),
new AuthenticationProperties(),
OpenIdConnectServerDefaults.AuthenticationScheme);
// Set the list of scopes granted to the client application.
ticket.SetScopes(
/* openid: */ OpenIdConnectConstants.Scopes.OpenId,
/* email: */ OpenIdConnectConstants.Scopes.Email,
/* profile: */ OpenIdConnectConstants.Scopes.Profile,
/* offline_access: */ OpenIdConnectConstants.Scopes.OfflineAccess);
return SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme);
}
}
客户端方法:
login(email, password) {
var deferred = q.defer();
var payload = {
'grant_type': 'password',
'username': email,
'password': password,
'scope': 'openid offline_access'
};
var url = this.authContextConfiguration.baseUrl + 'connect/token';
$.ajax({
url: url,
type: 'POST',
contentType: 'application/x-www-form-urlencoded',
data: payload,
success: function (data) {
// store the access token / everything else //
deferred.resolve();
},
error: function (req) {
var error = {
message: req.responseJSON.error_description || 'There was an error when signing in.'
};
deferred.reject(error);
}
});
return deferred.promise;
}
twoFactorLogin(email, password) {
var deferred = q.defer();
var payload = {
'username': email,
'password': password
}
var url = this.authContextConfiguration.baseUrl + 'connect/authorize';
$.ajax({
url: url,
type: 'POST',
contentType: 'application/x-www-form-urlencoded',
data: payload,
success: function (data) {
deferred.resolve(data);
},
error: function (req) {
var error = {
message: req.responseJSON.error_description || 'There was an error generating your two factor code.'
};
deferred.reject(error);
}
});
return deferred.promise;
}
verifyTwoFactorCode(id, code, remember) {
var deferred = q.defer();
var payload = {
'username': id,
'code': code,
'rememberMe': remember
}
var url = this.authContextConfiguration.baseUrl + 'connect/authorize';
$.ajax({
url: url,
type: 'POST',
contentType: 'application/x-www-form-urlencoded',
data: payload,
success: function (data) {
deferred.resolve(data);
},
error: function (req) {
var error = {
message: req.responseJSON.error_description || 'There was an error verifying your two factor code.'
};
deferred.reject(error);
}
});
return deferred.promise;
}