如果声明为空或不存在(非身份验证),则全局重定向回首页
Global redirect back to front page if claim is empty or does not exist (NOT identity verification)
澄清一下:我不是谈论基于声明的身份验证。
我正在构建一个应用程序,我在其中很好地使用了 Identity 2.2 来提供验证。足以满足我的需求。
我的问题是,一旦用户登录,只有第一页可以广泛访问,而无需在用户的“会话”中存储其他信息。特别是,当用户点击一个主要的内部项目时(为方便起见,我们称其为“客户模块”,该客户的 Guid 存储在用户持有的声明中。这样,用户可以从页面到页面,并且仍然在每个页面上显示相同客户的数据,而不管该页面要显示的数据块是多少。此声明仅 刷新 时有所不同 return 到主页并点击另一个客户。
为了安全起见,我想确保如果声明被意外删除或设置为空,用户将被分流回主页,无论他们在系统中的什么位置,最好是不必输入代码在每个控制器的每个页面操作中。
建议?或者我完全错误地利用索赔?因为如果不同方法的优势足够引人注目,那么在项目中进行掉头还为时过早。
编辑:
只是为了让人们知道我的解决方案:因为只有一组人会访问这个应用程序(与公司互动的用户,这个应用程序是为了记录互动和“公司信息”),我决定使用一个基础控制器。用户将能够登录并查看公司列表,而不会遇到任何派生自 BaseController
的页面,但是一旦他们选择了要与之合作的公司,他们就需要设置 Claims 才能维护页面-按页面联系该公司的信息。只有当他们选择不同的公司时,这些信息才会被重置,但由于索赔总是有可能被禁用,我需要一些东西来自动将他们重定向回公司列表以重新设置索赔。 BaseController 仅供那些显示一家公司特定信息的页面使用,是完美的解决方案。
基本控制器很简单。只需创建一个名为 BaseController 的控制器,您就可以开始比赛了。更改任何需要与此基本控制器配合使用的控制器,使其 public class YourOtherController : BaseController
.
我最初尝试创建一个 Initialize
方法来处理所有事情,但是 运行 遇到了一个相当大的问题:我无法成功地访问和写入我的声明。例如,我能够阅读我的声明但不能使用我的 ClaimWriter 扩展,或者我能够使用我的 ClaimWriter 扩展但一开始就无法阅读声明。由于 Initialize
在堆栈中太低而无法实际执行这两件事,我放弃了它并转而使用 OnActionExecuted
方法,最终成功了。我的代码最终是这样的:
public class BaseController : Controller {
private ApplicationDbContext db = new ApplicationDbContext();
protected override void OnActionExecuted(ActionExecutedContext filterContext) {
base.OnActionExecuted(filterContext);
var principal = ClaimsPrincipal.Current.Identities.First();
var company = User.GetClaimValue("CWD-Company");
var prospect = User.GetClaimValue("CWD-Prospect");
if(string.IsNullOrEmpty(company)) {
filterContext.HttpContext.Response.Clear();
filterContext.HttpContext.Response.Redirect("/");
filterContext.HttpContext.Response.End();
}
if(!string.IsNullOrEmpty(company) && string.IsNullOrEmpty(prospect)) {
var id = new Guid(company);
var prospecting = db.Prospecting
.Where(x => x.CompanyId.Equals(id))
.Select(x => x.ProspectingId)
.ToList().SingleOrDefault();
if(prospecting.Equals(Guid.Empty)) { // null prospecting
User.AddUpdateClaim("CWD-Prospecting", "");
} else { // fill prospecting
User.AddUpdateClaim("CWD-Prospecting", Convert.ToString(prospecting));
}
}
}
}
我可能会更改 Prospecting 部分的 if(prospecting.Equals(Guid.Empty)
部分以自动创建数据库中的第一个条目(当然,除了 ProspectingId 和 CompanyId 之外的所有空值),但这目前有效。
你描述的声明很好用,不需要掉头。你需要的是一个 MVC 过滤器,授权过滤器。像这样:
public class MyAuthorisationFilter : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
var principal = HttpContext.Current.User as ClaimsPrincipal;
if(!principal.Claims.Any(c => c.Type == "My Claim Name"))
{
// user has no claim - do redirection
// you need to create 'AuthenticateAgain' route to your table of routes
// or you can do other means of redirection
filterContext.Result = new RedirectToRouteResult("AuthenticateAgain", new RouteValueDictionary());
}
}
}
然后您可以将其全局添加到您的过滤器配置中,但您必须从该过滤器中排除您的授权页面。或者在每个控制器的基础上应用——只要需要发生。
这是非常基本的过滤器形式 - 删除了许多检查,但它给出了如何进行的一般方向。
更新
- 这是关于
Authorise
属性的 good article。
- Here
AllowAnonymous
属性的使用说明
您使用它的方式 - 取决于您的场景。在大多数情况下,当你只向世界公开一个登录页面时 - 将此属性添加为全局过滤器就足够了(参见第二个 link,关于 RegisterGlobalFilters
的部分)然后撒上 [AllowAnonymous]
在 controllers/actions 之上,无需身份验证即可公开。
另一种方法是使用应用了您的属性的基本控制器。然后你所有的控制器都继承自这个基本控制器。当全局过滤器不削减它时,这就足够了:当您将不同的页面公开给不同的用户时的情况 - 想想公司和客户。您的公司控制器将继承具有 [CompaniesAuthFilter]
的 CompaniesBaseController
,而客户将从具有 [CustomersAuthFilter]
的 CustomersBaseController
继承。
澄清一下:我不是谈论基于声明的身份验证。
我正在构建一个应用程序,我在其中很好地使用了 Identity 2.2 来提供验证。足以满足我的需求。
我的问题是,一旦用户登录,只有第一页可以广泛访问,而无需在用户的“会话”中存储其他信息。特别是,当用户点击一个主要的内部项目时(为方便起见,我们称其为“客户模块”,该客户的 Guid 存储在用户持有的声明中。这样,用户可以从页面到页面,并且仍然在每个页面上显示相同客户的数据,而不管该页面要显示的数据块是多少。此声明仅 刷新 时有所不同 return 到主页并点击另一个客户。
为了安全起见,我想确保如果声明被意外删除或设置为空,用户将被分流回主页,无论他们在系统中的什么位置,最好是不必输入代码在每个控制器的每个页面操作中。
建议?或者我完全错误地利用索赔?因为如果不同方法的优势足够引人注目,那么在项目中进行掉头还为时过早。
编辑:
只是为了让人们知道我的解决方案:因为只有一组人会访问这个应用程序(与公司互动的用户,这个应用程序是为了记录互动和“公司信息”),我决定使用一个基础控制器。用户将能够登录并查看公司列表,而不会遇到任何派生自 BaseController
的页面,但是一旦他们选择了要与之合作的公司,他们就需要设置 Claims 才能维护页面-按页面联系该公司的信息。只有当他们选择不同的公司时,这些信息才会被重置,但由于索赔总是有可能被禁用,我需要一些东西来自动将他们重定向回公司列表以重新设置索赔。 BaseController 仅供那些显示一家公司特定信息的页面使用,是完美的解决方案。
基本控制器很简单。只需创建一个名为 BaseController 的控制器,您就可以开始比赛了。更改任何需要与此基本控制器配合使用的控制器,使其 public class YourOtherController : BaseController
.
我最初尝试创建一个 Initialize
方法来处理所有事情,但是 运行 遇到了一个相当大的问题:我无法成功地访问和写入我的声明。例如,我能够阅读我的声明但不能使用我的 ClaimWriter 扩展,或者我能够使用我的 ClaimWriter 扩展但一开始就无法阅读声明。由于 Initialize
在堆栈中太低而无法实际执行这两件事,我放弃了它并转而使用 OnActionExecuted
方法,最终成功了。我的代码最终是这样的:
public class BaseController : Controller {
private ApplicationDbContext db = new ApplicationDbContext();
protected override void OnActionExecuted(ActionExecutedContext filterContext) {
base.OnActionExecuted(filterContext);
var principal = ClaimsPrincipal.Current.Identities.First();
var company = User.GetClaimValue("CWD-Company");
var prospect = User.GetClaimValue("CWD-Prospect");
if(string.IsNullOrEmpty(company)) {
filterContext.HttpContext.Response.Clear();
filterContext.HttpContext.Response.Redirect("/");
filterContext.HttpContext.Response.End();
}
if(!string.IsNullOrEmpty(company) && string.IsNullOrEmpty(prospect)) {
var id = new Guid(company);
var prospecting = db.Prospecting
.Where(x => x.CompanyId.Equals(id))
.Select(x => x.ProspectingId)
.ToList().SingleOrDefault();
if(prospecting.Equals(Guid.Empty)) { // null prospecting
User.AddUpdateClaim("CWD-Prospecting", "");
} else { // fill prospecting
User.AddUpdateClaim("CWD-Prospecting", Convert.ToString(prospecting));
}
}
}
}
我可能会更改 Prospecting 部分的 if(prospecting.Equals(Guid.Empty)
部分以自动创建数据库中的第一个条目(当然,除了 ProspectingId 和 CompanyId 之外的所有空值),但这目前有效。
你描述的声明很好用,不需要掉头。你需要的是一个 MVC 过滤器,授权过滤器。像这样:
public class MyAuthorisationFilter : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
var principal = HttpContext.Current.User as ClaimsPrincipal;
if(!principal.Claims.Any(c => c.Type == "My Claim Name"))
{
// user has no claim - do redirection
// you need to create 'AuthenticateAgain' route to your table of routes
// or you can do other means of redirection
filterContext.Result = new RedirectToRouteResult("AuthenticateAgain", new RouteValueDictionary());
}
}
}
然后您可以将其全局添加到您的过滤器配置中,但您必须从该过滤器中排除您的授权页面。或者在每个控制器的基础上应用——只要需要发生。 这是非常基本的过滤器形式 - 删除了许多检查,但它给出了如何进行的一般方向。
更新
- 这是关于
Authorise
属性的 good article。 - Here
AllowAnonymous
属性的使用说明
您使用它的方式 - 取决于您的场景。在大多数情况下,当你只向世界公开一个登录页面时 - 将此属性添加为全局过滤器就足够了(参见第二个 link,关于 RegisterGlobalFilters
的部分)然后撒上 [AllowAnonymous]
在 controllers/actions 之上,无需身份验证即可公开。
另一种方法是使用应用了您的属性的基本控制器。然后你所有的控制器都继承自这个基本控制器。当全局过滤器不削减它时,这就足够了:当您将不同的页面公开给不同的用户时的情况 - 想想公司和客户。您的公司控制器将继承具有 [CompaniesAuthFilter]
的 CompaniesBaseController
,而客户将从具有 [CustomersAuthFilter]
的 CustomersBaseController
继承。