【问题标题】:How to Prevent Direct access to View in Asp.net Core如何防止直接访问 Asp.net Core 中的视图
【发布时间】:2019-02-06 22:46:37
【问题描述】:

我想阻止直接访问视图。当单击用户电子邮件中的确认链接时,我有一个显示已确认电子邮件的视图。但是,问题是该视图的Url可以直接访问,我只是希望在单击电子邮件中的链接时访问它。

我已尝试过此选项,但由于 UrlReferer 在 Asp.net 核心中不可用,因此一直出错。此代码在 asp.net core 中不起作用,请有人帮助我。

如何在 ASp.net Core 2.x 中访问这些值:

filterContext.HttpContext.Request.UrlReferrer
filterContext.HttpContext.Request.Url.Host
filterContext.HttpContext.Request.UrlReferrer.Host

我在 Stack-overflow 上找到的代码 - 但它需要 System.Web,这在 asp.net 核心中不可用。


public class NoDirectAccessAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (filterContext.HttpContext.Request.UrlReferrer == null ||
                    filterContext.HttpContext.Request.Url.Host != filterContext.HttpContext.Request.UrlReferrer.Host)
            {
            filterContext.Result = new RedirectToRouteResult(new
                           RouteValueDictionary(new { controller = "Home", action = "Index", area = "" })); 
        }
    }
}

推荐使用自定义属性的方式

[NoDirectAccess]
public ActionResult MyActionMethod()

【问题讨论】:

  • 我试过这个但总是返回 null - 我需要从 ActionExecutingContext string referer = context.HttpContext.Request.Headers["Referer"].ToString();
  • @LyoidLopes 可能您需要重构它的验证方式。 UrlReferer 很容易通过。另外,如果用户已经确认了邮件,但是通过在浏览器中直接粘贴 URL 两次来访问视图,您如何确定是否应该显示该视图? IMO,如果用户已确认电子邮件,只需将EmailConfrimed=true 存储在某处(数据库/JWT/...)。现在您可以使用过滤器/策略来防止直接访问视图
  • 我正在尝试,但要阻止用户再次预览,我需要获取 UrlReferer。如果这很容易,你能给我一个过滤器的例子。当他们单击电子邮件链接时会显示视图。但是当他们复制粘贴相同的链接时,仍然可以看到电子邮件确认消息。我只想要一个过滤器来防止直接访问 url。但为此我需要 System.Web - 我不能在 Asp.net 核心中使用它 - 因此,如何在过滤器中获取 UrlReferer 的值。

标签: asp.net asp.net-core


【解决方案1】:
  1. 如果您确实需要UrlReferer,请创建如下过滤器:
    public class NoDirectAccessAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            var canAcess= false;

            // check the refer
            var referer= filterContext.HttpContext.Request.Headers["Referer"].ToString(); 
            if(!string.IsNullOrEmpty(referer)){
                var rUri = new System.UriBuilder(referer).Uri;
                var req = filterContext.HttpContext.Request;
                if(req.Host.Host==rUri.Host && req.Host.Port == rUri.Port && req.Scheme == rUri.Scheme ){
                    canAcess=true;
                }
            }

            // ... check other requirements

            if(!canAcess){
                filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new { controller = "Home", action = "Index", area = "" })); 
            }
        }
    }

现在您可以使用 [NoDirectAccess] 来装饰您的操作方法:

        [NoDirectAccess]
        public IActionResult Privacy()
        {
            return View();
        }
  1. 不建议使用Referer 来授权请求​​,因为很容易伪造UrlReferer 的HTTP Header。

IMO,当用户单击确认链接时,最好将EmailConfirmed=true 存储在某处。然后你可以在验证时检查EmailConfirmed是否等于true

    public class NoDirectAccessAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            var canAcess= false;

            // check the `EmailConfirmed` state

            // ... check other requirements

            if(!canAcess){
                filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new { controller = "Home", action = "Index", area = "" })); 
            }
        }
    }

【讨论】:

    【解决方案2】:

    一般来说,依赖请求的“referer”属性并不是一个好主意。浏览器实现可能不同,因此您可能会收到不一致的值。

    如果 URL 是“公开的”,则您无法阻止用户在浏览器上键入该 URL。但是,您可以做的是向“获取”请求添加验证-例如,需要有关 URL 的一些附加信息-在您的情况下,例如用户 ID 和验证“代码”。这就是 asp.net 身份生成用于电子邮件确认的 URL 的方式。它包括用户 ID 和确认码。如果没有这些值作为 URL 的一部分,则可能会使请求无效并重定向到另一个页面(而不是电子邮件确认页面)。

    例如,在 Razor 页面中,以下是如何验证请求的示例。 (重点是,它需要来自用户的额外输入,而不是普通的 URL。。)(你也可以在 MVC 中做类似的事情。)

           public async Task<IActionResult> OnGetAsync(string userId, string code)
            {
                if (userId == null || code == null)
                {
                    return RedirectToPage("/Index");
                }
    
                var user = await _userManager.FindByIdAsync(userId);
                if (user == null)
                {
                    throw new ApplicationException($"Unable to load user with ID '{userId}'.");
                }
    
                var result = await _userManager.ConfirmEmailAsync(user, code);
                if (!result.Succeeded)
                {
                    throw new ApplicationException($"Error confirming email for user with ID '{userId}':");
                }
    
                return Page();
            }
    

    上述代码验证的 URL 类似于:

    http://[baseurl]/Account/ConfirmEmail?userId=ca5416dd-c93a-49a5-8fac-a9986dc91ed7&code=CfDJ8DWvHoaRg6JAv0rZ75jyEVx
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-04-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-16
      • 1970-01-01
      相关资源
      最近更新 更多