我想创建一个自定义用户,对其进行身份验证,然后使用Identity Server 3将用户声明返回到Angular应用程序中。我已经查看了示例,特别是CustomUserService项目。
编辑:根据进展更新了问题:
在startup.cs文件中,我加载了范围和客户端。
var idServerServiceFactory = new IdentityServerServiceFactory()
.UseInMemoryClients(Clients.Get())
.UseInMemoryScopes(Scopes.Get());
//.UseInMemoryUsers(Users.Get());
接下来是在UserServices.cs文件中的重写部分。
public override Task AuthenticateLocalAsync(LocalAuthenticationContext context)
{
string hashedPassword = string.Empty;
string salt = string.Empty;
//pull users
using (IdentityModelContext ctx = new IdentityModelContext())
{
IIdSrvUserRepository ur = new IdSrvUserRepository(ctx);
Users = ur.GetAll().ToList();
}
//salt curent password
var user = Users.SingleOrDefault(x => x.UserName == context.UserName);
if (user != null)
{
salt = user.Salt;
hashedPassword = IqUtils.GenerateSaltedPassword(context.Password, salt);
if (user.UserName == context.UserName && hashedPassword == user.Password)
{
try
{
context.AuthenticateResult = new AuthenticateResult(user.Subject, user.UserName);
}
catch (Exception ex)
{
string msg = $"<-- Login Error: Message: {ex.Message}, Inner Exception:{ex.InnerException} --->";
myLogger log = new myLogger("IdentityServer");
}
}
}
return Task.FromResult(0);
}
我遇到困难的地方在于GetProfileDataAsync方法。我无法弄清如何向客户端添加声明,或者是否需要调用第二个客户端。
该应用程序是一个通过Idsrv进行身份验证的angular客户端。我已创建了一个客户端。
//Angular client authentication
new Client
{
ClientId = "iqimplicit",
ClientName = "IQ Application (Implicit)",
Flow = Flows.Implicit,
AllowAccessToAllScopes = true,
IdentityTokenLifetime = 300,//default value is 5 minutes this is the token that allows a user to login should only be used once
AccessTokenLifetime = 3600, // default is one hour access token is used for securing routes and access to api in IQ
RequireConsent = false,
RequireSignOutPrompt = true,
AllowedScopes = new List<string>
{
//no clue if this is correct
StandardScopes.Profile.Name
},
RedirectUris = new List<string>
{
angularClient + "callback.html"
},
PostLogoutRedirectUris = new List<string>()
{
//redirect to login screen
angularClient
}
}
根据这里的SO帖子,我正在尝试将声明添加到返回给客户端的访问令牌中。
我定义的范围只适用于资源。 我认为我需要创建一个类似于被注释掉的部分的身份第二个范围?
return new List<Scope>
{
StandardScopes.OpenId,
StandardScopes.ProfileAlwaysInclude,
StandardScopes.Address,
new Scope
{
Name = "appmanagement",
DisplayName = "App Management",
Description = "Allow application to management.",
Type = ScopeType.Resource,
Claims = new List<ScopeClaim>()
{
new ScopeClaim("role", false),
new ScopeClaim("Name", true),
new ScopeClaim("GivenName", true),
new ScopeClaim("FamilyName", true),
new ScopeClaim("Email", true),
},
},
// new Scope
// {
// Name = "iquser",
// DisplayName = "User",
// Description = "Identifies the user",
// Type = ScopeType.Identity,
// Claims = new List<ScopeClaim>()
// {
// new ScopeClaim("Name", true)
// }
// }
};
}
}
}
我希望传递回去的信息如上所示,包括姓名、名字、姓氏和电子邮件。
尝试遵循之前提到的 SO 帖子中的评论,覆盖了 GetProfileDataAsync
方法,该方法应该获取用户的信息。
public override Task GetProfileDataAsync(ProfileDataRequestContext context)
{
// issue the claims for the user
var user = Users.SingleOrDefault(x => x.Subject == context.Subject.GetSubjectId());
if (user != null)
{
if(context.RequestedClaimTypes != null)
try
{
if (context.RequestedClaimTypes != null)
{
List<Claim> newclaims = new List<Claim>();
foreach (Claim claim in context.Subject.Claims)
{
if (context.RequestedClaimTypes.Contains(claim.Type))
{
newclaims.Add(claim);
}
}
context.IssuedClaims = newclaims;
}
}
catch (Exception ex)
{
string msg = $"<-- Error Getting Profile: Message: {ex.Message}, Inner Exception:{ex.InnerException} --->";
myLogger log = new myLogger("IdentityServer");
}
}
//return Task.FromResult(context.IssuedClaims);
return Task.FromResult(0);
}
}
我现在遇到了困难,尽管我已经看到了我定义的 context.RequestedClaimTypes
中所述的声明,但是在 claim.Type
中从来没有匹配上,因为它总是包含idsrv声明的基础属性。
由于这是一个自定义数据库,所有发生在claims中的信息都存储在数据库的Users表中,而不是Claims表中。 我试图将用户表中每个字段的值映射到Claim值。
更新 我已经回到了范围并将以下声明添加到标识范围类型中。
new Scope
{
Name = "iuser",
DisplayName = "User",
Description = "Identifies the user",
Type = ScopeType.Identity,
Claims = new List<ScopeClaim>()
{
new ScopeClaim(Constants.ClaimTypes.Name, alwaysInclude: true),
new ScopeClaim(Constants.ClaimTypes.GivenName, alwaysInclude: true),
new ScopeClaim(Constants.ClaimTypes.FamilyName, alwaysInclude: true),
new ScopeClaim(Constants.ClaimTypes.Email, alwaysInclude: true),
}
}
初始身份验证已经完成,回调函数中可以看到作用域的评估。然而,我仍然困惑于如何获取应用于这些作用域的数据库中的值。代码的这一部分(如预期的那样)正在寻找 System.Security.Claims.Claim
类型。这是确定如何获取用户属性作为声明应用和返回的声明值的停止点。
此时,我被重定向回了 Angular 应用程序,但是 accesstoken 对象为空,没有用户信息。
在这一点上,我该如何将自己的值作为声明插入到 context.IssuedClaims
中?
提前致谢。
IUserService
实现的目的。 - John Korsnes