向 Azure 移动服务用户添加自定义角色(Google、Twitter、Facebook、Microsoft)
Adding custom Roles to Azure Mobile Services User (Google, Twitter, Facebook, Microsoft)
我有一个 .NET Azure 移动服务项目,其中包含一些我想使用典型授权属性保护的控制器。我可以创建一个角色 table 和一个 UserProfiles table,并将通过 Google、Facebook 等认证的各种用户与我的角色 table 中的角色相关联。
我的问题是:如何在身份验证完成后但在授权过滤器的 OnAuthorize 方法运行之前将 Roles 声明添加到 ServiceUsers?这甚至可能吗?
我想做的事的例子:
[Authorize(Roles = "admin")]
public async Task<IHttpActionResult> Put(int id, MyDto dto){...}
粗略的 table 示例:
Roles
id | name
1 | user
2 | admin
UserProfiles
id | externalLoginId | favoriteColor
1 | Google:<ServiceUser.Id> | blue
UserRoles (Linking Table)
roleId | userId
2 | 1
编辑:
一个选项可能是创建我自己的操作过滤器来覆盖 Authorize 过滤器属性,并且在 OnAuthorize 方法中我可以查询 UserProfiles 和 Roles tables 以获取当前用户的角色,然后检查在 Authorize 对象的 Roles 属性 中指定的角色以确定用户是否具有访问权限。但不知何故,感觉管道中应该有一个更早的位置,我可以拦截它,以便将 Roles 声明添加到当前用户。
您可以将 Role Claim 添加到用户 Principal,例如:
new ClaimsIdentity(new Claim[]
{
new Claim(ClaimTypes.NameIdentifier, loginName),
new Claim(ClaimTypes.Role, "admin"),
};
但是您会仅仅依靠验证获取的声明信息来提供基于角色的授权吗?
您无论如何都需要通过 AuthorizeLevelAttribute 或其他一些自定义属性来处理授权和验证,以装饰您的方法;并且您需要对验证用户角色所需的行为进行编程。然后需要在 OnAuthorization 方法覆盖中完成如何验证角色成员身份,这取决于您:您可以查询 Db、Graph API,否则.我认为目前没有其他管理权限的选项,文档和示例也以这种方式指向
这里有一些很好的参考:
我找到了解决方案。它涉及:
创建我自己的 ServiceTokenHandler 并覆盖 CreateServiceUser 方法以在调用 base.CreateServiceUser(claimsIdentity) 之后添加逻辑,该逻辑试图在我的 UserProfile table 中找到角色链接到 claimsIdentity 中指定的用户。如果找到角色,它会将新的角色声明添加到 claimsIdentity 的声明集合中。
public class RolesServiceTokenHandler : ServiceTokenHandler
{
public RolesServiceTokenHandler(HttpConfiguration config) : base(config)
{
}
public override ServiceUser CreateServiceUser(ClaimsIdentity claimsIdentity)
{
var serviceUser = base.CreateServiceUser(claimsIdentity);
if (serviceUser != null && serviceUser.Identity.IsAuthenticated)
{
var dataContext = new AllergenDerivativesContext();
var userId = serviceUser.Id;
var userProfile = dataContext.UserProfiles.Include(u => u.Roles).FirstOrDefault(u => u.ExternalUserId == userId);
if (userProfile == null)
{
//If the user profile does not exist, then create it and assign it to the User role by default.
userProfile = new UserProfile();
//Set the ExternalUserId for the UserProfile to the current User's External Login Id.
userProfile.ExternalUserId = userId;
//Get the "User" Role Entity.
var userRole = dataContext.Roles.FirstOrDefault(r => r.Name == Roles.User);
//Initialize the roles collection for the new UserProfile
//And add the existing role to the collection.
userProfile.Roles = new List<Role> { userRole };
//Add the new UserProfile to the database and save the changes.
dataContext.UserProfiles.Add(userProfile);
dataContext.SaveChanges();
}
//Get the roles for the UserProfile and add role claims to the ServiceUser's primary Identity.
foreach (var role in userProfile.Roles)
{
((ClaimsIdentity)serviceUser.Identity).AddClaim(new Claim(ClaimTypes.Role, role.Name));
}
}
return serviceUser;
}
}
使用 autofac 注册新的 RolesServiceTokenHandler 作为 IServiceTokenHandler,这样当应用程序请求 IServiceTokenHandler 时,autofac returns 新的 RolesServiceTokenHandler。
在 WebApiConfig.cs 文件的静态 Register 方法中,更改对 ServiceConfig.Initialize 的调用,使其看起来像:
HttpConfiguration config = ServiceConfig.Initialize(new ConfigBuilder(options, (httpConfig, autofac) =>
{
autofac.RegisterType<RolesServiceTokenHandler>().As<IServiceTokenHandler>();
}));
我有一个 .NET Azure 移动服务项目,其中包含一些我想使用典型授权属性保护的控制器。我可以创建一个角色 table 和一个 UserProfiles table,并将通过 Google、Facebook 等认证的各种用户与我的角色 table 中的角色相关联。
我的问题是:如何在身份验证完成后但在授权过滤器的 OnAuthorize 方法运行之前将 Roles 声明添加到 ServiceUsers?这甚至可能吗?
我想做的事的例子:
[Authorize(Roles = "admin")]
public async Task<IHttpActionResult> Put(int id, MyDto dto){...}
粗略的 table 示例:
Roles
id | name
1 | user
2 | admin
UserProfiles
id | externalLoginId | favoriteColor
1 | Google:<ServiceUser.Id> | blue
UserRoles (Linking Table)
roleId | userId
2 | 1
编辑:
一个选项可能是创建我自己的操作过滤器来覆盖 Authorize 过滤器属性,并且在 OnAuthorize 方法中我可以查询 UserProfiles 和 Roles tables 以获取当前用户的角色,然后检查在 Authorize 对象的 Roles 属性 中指定的角色以确定用户是否具有访问权限。但不知何故,感觉管道中应该有一个更早的位置,我可以拦截它,以便将 Roles 声明添加到当前用户。
您可以将 Role Claim 添加到用户 Principal,例如:
new ClaimsIdentity(new Claim[]
{
new Claim(ClaimTypes.NameIdentifier, loginName),
new Claim(ClaimTypes.Role, "admin"),
};
但是您会仅仅依靠验证获取的声明信息来提供基于角色的授权吗?
您无论如何都需要通过 AuthorizeLevelAttribute 或其他一些自定义属性来处理授权和验证,以装饰您的方法;并且您需要对验证用户角色所需的行为进行编程。然后需要在 OnAuthorization 方法覆盖中完成如何验证角色成员身份,这取决于您:您可以查询 Db、Graph API,否则.我认为目前没有其他管理权限的选项,文档和示例也以这种方式指向
这里有一些很好的参考:
我找到了解决方案。它涉及:
创建我自己的 ServiceTokenHandler 并覆盖 CreateServiceUser 方法以在调用 base.CreateServiceUser(claimsIdentity) 之后添加逻辑,该逻辑试图在我的 UserProfile table 中找到角色链接到 claimsIdentity 中指定的用户。如果找到角色,它会将新的角色声明添加到 claimsIdentity 的声明集合中。
public class RolesServiceTokenHandler : ServiceTokenHandler { public RolesServiceTokenHandler(HttpConfiguration config) : base(config) { } public override ServiceUser CreateServiceUser(ClaimsIdentity claimsIdentity) { var serviceUser = base.CreateServiceUser(claimsIdentity); if (serviceUser != null && serviceUser.Identity.IsAuthenticated) { var dataContext = new AllergenDerivativesContext(); var userId = serviceUser.Id; var userProfile = dataContext.UserProfiles.Include(u => u.Roles).FirstOrDefault(u => u.ExternalUserId == userId); if (userProfile == null) { //If the user profile does not exist, then create it and assign it to the User role by default. userProfile = new UserProfile(); //Set the ExternalUserId for the UserProfile to the current User's External Login Id. userProfile.ExternalUserId = userId; //Get the "User" Role Entity. var userRole = dataContext.Roles.FirstOrDefault(r => r.Name == Roles.User); //Initialize the roles collection for the new UserProfile //And add the existing role to the collection. userProfile.Roles = new List<Role> { userRole }; //Add the new UserProfile to the database and save the changes. dataContext.UserProfiles.Add(userProfile); dataContext.SaveChanges(); } //Get the roles for the UserProfile and add role claims to the ServiceUser's primary Identity. foreach (var role in userProfile.Roles) { ((ClaimsIdentity)serviceUser.Identity).AddClaim(new Claim(ClaimTypes.Role, role.Name)); } } return serviceUser; } }
使用 autofac 注册新的 RolesServiceTokenHandler 作为 IServiceTokenHandler,这样当应用程序请求 IServiceTokenHandler 时,autofac returns 新的 RolesServiceTokenHandler。
在 WebApiConfig.cs 文件的静态 Register 方法中,更改对 ServiceConfig.Initialize 的调用,使其看起来像:
HttpConfiguration config = ServiceConfig.Initialize(new ConfigBuilder(options, (httpConfig, autofac) =>
{
autofac.RegisterType<RolesServiceTokenHandler>().As<IServiceTokenHandler>();
}));