如何防止在Asp.net Core中直接访问View

时间:2019-02-06 22:46:37

标签: asp.net asp.net-core

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

我已经尝试过此选项,但是由于 UrlReferer 在Asp.net核心中不可用,因此会不断出错。该代码无法在asp.net核心中运行,请有人帮我。

如何在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()

2 个答案:

答案 0 :(得分:0)

  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标头很容易。

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 = "" })); 
            }
        }
    }

答案 1 :(得分:0)

通常,在请求上依赖“ 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