C# 基于ASP.NET MVC 5身份用户在实体上构建筛选器

C# 基于ASP.NET MVC 5身份用户在实体上构建筛选器,c#,asp.net-mvc,asp.net-identity,C#,Asp.net Mvc,Asp.net Identity,我有一个调查平台,上面有一个商店列表的所有分数 我需要为每个用户提供基于其所在区域(地区)的商店 我在我的MVC项目中使用了Microsoft Identity,我只找到了两个解决方案: 1-为每个区域构建一个概要文件,这样我就可以根据登录用户的概要文件名-dbContext.Where(location==profileName)进行筛选 2-扩展ApplicationUser以包括区域,这样我就可以使用dbContext.Where(location==User.Identity.GetLo

我有一个调查平台,上面有一个商店列表的所有分数

我需要为每个用户提供基于其所在区域(地区)的商店

我在我的MVC项目中使用了Microsoft Identity,我只找到了两个解决方案:

1-为每个区域构建一个概要文件,这样我就可以根据登录用户的概要文件名-dbContext.Where(location==profileName)进行筛选

2-扩展ApplicationUser以包括区域,这样我就可以使用dbContext.Where(location==User.Identity.GetLocation())进行筛选

还是其他选择

我已经能够实施第二个选项:

门店型号:

public enum PTLocationDistrict
{
    [Display(Name = "Aveiro")]
    Aveiro = 1,
    [Display(Name = "Beja")]
    Beja = 2,
    [Display(Name = "Braga")]
    Braga = 3
}

[Table("Stores")]
public class Store
{
    [Key]
    public int Id { get; set; }
    public DateTime DateCreated { get; set; }
    public DateTime DateModified { get; set; }
    public string Name { get; set; }
    public string Address { get; set; }
    public PTLocationDistrict District { get; set; }
}
身份应用程序用户:

public class ApplicationUser : IdentityUser
{
    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
    {
        // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
        var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);

        // Add custom user claims here
        userIdentity.AddClaim(new Claim("PTLocationDistrict", this.PTLocationDistrict.ToString()));

        return userIdentity;
    }

    // Additional properties for the Application User
    public PTLocationDistrict? PTLocationDistrict { get; set; }
}
仪表板报表计数服务:

public int GetCountToday(PTLocationDistrict? ptLocationDistrict)
{
    try
    {
        var today = DateTime.Today;

        IQueryable<SurveySession> surveySessions = _dbContext.SurveySessions.AsNoTracking().AsQueryable();

        if (ptLocationDistrict != null)
        {
            surveySessions = surveySessions.Where(ss => ss.Location.District == ptLocationDistrict.Value);
        }

        int count = surveySessions
                            .Where(p => p.DateCreated >= today)
                            .Count();

        return count;
    }
    catch (Exception error)
    {
        _logger.Error("[Error in SurveyService.GetCountToday" - Error: " + error + "]");

        return 0;
    }
}

这些信息似乎不用于标识(基于位置拒绝访问)。因此,如果您有一个“Person”表,您可以将位置存储在那里,在标识模型之外,并在位置字段的联接中使用此表

如果不是,我只想添加一个位置声明。优点是,您可以读取声明,而无需从数据库中查找字段。您可以使用
User.Identity.GetLocation()
,前提是该扩展读取包含位置的声明

您可以使用字段位置扩展IdentityUser,并根据字段添加声明。但是,如果将声明添加到
AspNetUserClaims
表中,则不必这样做,因为它不太可能更改。在这种情况下,索赔将自动添加到标识中

请注意,仅当用户注销并再次登录,或令牌过期时,才会更新声明的值

--更新--

您可以创建CustomClaimType,如下所示:

public const string LocationClaimType = "https://schemas.mycompany.com/claims/location";
这其实并不重要,只要它能够唯一地识别索赔

关于AspNetUserClaims表,没有太多要说的。插入claimtype为自定义claimtype的记录,并为特定用户设置值。它会自动添加到标识中。您还可以使用代码向用户添加声明

在控制器中:

var identity = (System.Security.Claims.ClaimsIdentity)User.Identity;
var res = identity.Claims.FirstOrDefault(c => c.ValueType == LocationClaimType)?.Value;
您可以使用上面的代码扩展标识(使用GetLocation)。你可以为CompanyId做同样的事情


在这两种情况下,属性都不太可能更改,您不需要调用数据库来获取这些附加信息。

恐怕这个问题有点宽泛。首先,你是如何确定位置的?乔治郊游?嗨,谢谢!用户的位置是在注册过程中指定的,基于国家的地区列表(在本例中为葡萄牙),该列表将筛选门店列表作为旁注:我不会将PTLocationDistrict实现为null。改为添加None=0并将其设置为默认值。为什么,您认为这是一种不好的做法?因此,我必须将过滤器更改为“ptLocationDistrict!=ptLocationDistrict.None”正确吗?在使用您的建议后,代码似乎变得更干净,没有可为空的值,我们需要从中创建特殊的转换。这个“return PTLocationDistrict.None;”比“return null”读得更好。此外,我检查了您共享的问题,但只是阅读了@Maarten jansonius解决方案,使用None是有意义的,因为我们确信已经定义了一个值而不是null。嗨,谢谢!我没有找到关于使用AspNetUserClaims表的太多信息。我已经在我的项目中创建了一个User.Identity.GetCompanyId(),这样我就可以过滤每个用户的数据,我非常熟悉,但我不知道这是否是您提供的两个选项中最好的一个。GetCompanyId做什么?它是调用数据库还是过滤声明?在“业务”上下文中是否有类似于“Person”的表?GetCompanyId从users表中获取已登录用户的公司id。它不过滤,它是存储在identity表中的id,因为我没有person表,只有users。我发现没有很好的例子可以在索赔表中尝试这种方法。在结果中应用过滤器之前,我不知道如何创建和管理所有内容。您能否帮助理解代码的逻辑,用户在登录之前或之后在何处和何时定义其声明?在我创建用户声明的那一刻?我有麻烦把你的代码放在我的…我终于让它运行起来,我应该分享代码,这样我们就可以讨论你的解决方案应用到它?我认为你的解决方案更适合长期应用
public const string LocationClaimType = "https://schemas.mycompany.com/claims/location";
var identity = (System.Security.Claims.ClaimsIdentity)User.Identity;
var res = identity.Claims.FirstOrDefault(c => c.ValueType == LocationClaimType)?.Value;