【问题标题】:How to get whether user is authenticated by custom Action Filter in ASP.NET MVC View?如何获取用户是否通过 ASP.NET MVC 视图中的自定义操作筛选器进行身份验证?
【发布时间】:2016-12-23 20:09:34
【问题描述】:

我有一个使用我的身份验证过滤器的操作方法:

public class TutorAuthenticationAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var req = filterContext.HttpContext.Request;
        var auth = req.Headers["Authorization"];
        if (!string.IsNullOrEmpty(auth))
        {
            var cred = System.Text.Encoding.ASCII.GetString(Convert.FromBase64String(auth.Substring(6))).Split(':');
            var user = new { Name = cred[0], Password = cred[1] };
            if (userService.AuthorizeTutor(user.Name, user.Password))
            {
                return;
            }
        }
        filterContext.HttpContext.Response.AddHeader("WWW-Authenticate", $"Basic realm= {BasicRealm}");

        filterContext.Result = new HttpUnauthorizedResult();
    }
}

然后我想在主页上为已通过这种方式进行身份验证的用户显示一些内容,但这在我的视图中不起作用:(

@if (Request.IsAuthenticated)
{
    <h1>Hello</h1>
}

我知道它不起作用,因为我不使用 Identity,但有什么方法可以做到这一点?

感谢您的回答:)

【问题讨论】:

  • userService 是从哪里来的?它是否有一些属性可以返回经过身份验证的状态?
  • DI,我只是省略了一些不重要的属性...它只是返回真/假
  • 该过滤器会自动将一些数据存储到 cookie 中,以便存储经过身份验证的状态
  • 你介意解决方案是否使用了“身份”吗??
  • 当你说你想要一个没有身份的解决方案时,这是否也排除了将 Thread.CurrentPrincipal 设置为 GenericPrincipal 的可能性?

标签: c# asp.net


【解决方案1】:

我想,在标题中发送登录名和密码是不安全的。更好的解决方案是验证用户一次。并且检查后,您可以检查所有请求。

例如,如果您使用FormsAuthentication 和 authCookie,则非常简单:

  1. 在 web.config 中设置 auth mentod:&lt;authentication mode="Forms" /&gt;

  2. 当登录名和密码有效时,使用FormsAuthentication.SetAuthCookie(userName, createPersistentCookie = true); 此步骤仅在用户登录应用程序时执行一次。

  3. 然后您可以在视图中使用属性this.Request.IsAuthenticated 或在控制器(或过滤器)中使用HttpContext.Current.Request.IsAuthenticated

  4. 它可以在控制器或操作(控制器中的公共方法)上使用属性[Authorize]。当请求未通过身份验证时,请求被重定向到默认(或在 web.config 中设置)登录页面。

【讨论】:

  • 我认为在标头中发送登录名和密码并不安全(当您使用 HTTPS 时)。如果它解决了我的问题,我会尝试检查一些关于 FormsAuthentication 的文档:)
  • 这很好用,但我发现一篇关于 FormsAuthentication 已过时的文章,因为它不在 Owin 上运行(在我的情况下这无关紧要)
【解决方案2】:

为请求对象创建一个新的扩展方法,例如 (IsUserAuthenticated()) 并在该方法中检查用户是否有效。 完成此操作后,您可以像使用 Request.IsAuthenticated 属性一样使用这个新的扩展方法。

以下是示例代码,您需要根据需要对其进行调整。 (专门针对

userservice 

初始化)

public class RequestValidator
{
    public bool IsValid(HttpRequest request)
    {
       bool isValid  = false;

       //TODO: Intitialize your userService here, may be using DI or a concrete object creation depending on your implementation

       var auth = request.Headers["Authorization"];
       if (!string.IsNullOrEmpty(auth))
       {
           var cred = System.Text.Encoding.ASCII.GetString(Convert.FromBase64String(auth.Substring(6))).Split(':');
           var user = new { Name = cred[0], Password = cred[1] };

           isValid = userService.AuthorizeTutor(user.Name, user.Password))            
       }

      return isValid; 
    }
}

你的属性会这样变化

public class TutorAuthenticationAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var req = filterContext.HttpContext.Request;
        RequestValidator validator = new RequestValidator(); 
        if(validator.IsValid(request))
        {
            return; 
        }

        filterContext.HttpContext.Response.AddHeader("WWW-Authenticate", $"Basic realm= {BasicRealm}");

        filterContext.Result = new HttpUnauthorizedResult();
    }
}

在视图上使用的扩展方法将是

public static class Extensions
{
    public static bool IsUserAuthenticated(this HttpRequest request)
    {
        RequestValidator validator = new RequestValidator(); 
        return validator.IsValid(request); 
    }
}

这样使用

@if(Request.IsUserAuthenticated())
{
     <p>Hello</p>
}

【讨论】:

  • 但是如何检查用户是否有效?
  • 感谢您的回答,但这不能正常工作。你好只显示在需要身份验证的页面上 - 在用户输入正确的用户名和密码后,我什至需要在其他页面上显示它。 (我有一种感觉,也许我需要以某种方式访问​​它间接使用的 cookie?)
  • 您可以将授权码替换为cookies。
【解决方案3】:

如果您想传递指示用户是否经过身份验证的布尔值,那么仅使用模型对象并将其传递给视图可能是有意义的。

或者也许您应该检查您的表单身份验证以使Request.IsAuthenticated 正常工作。 This thread 将有助于开始挖掘。

另一种选择是考虑使用 IAuthorizationFilter 而不是自定义操作过滤器。 This thread 将是一个起点。

希望有帮助!

【讨论】:

  • 谢谢,我使用了第二个选项(正如 ksciana 之前建议的那样),我认为其他选项不会解决问题
【解决方案4】:

为了满足您的目的,您需要将HttpContext.User 设置为某个有效的IPrincipal。 因此,如果根据您的标准,用户是有效的,您只需要创建一个GenericPrinicpal 并使用您刚刚创建的实例设置HttpContext.User

类似这样的:

var genericIdentity=new GenericIdentity(user.Name,  "CustomAuthType");
var genericPrincipal=new GenericPrincipal(genericIdentity, null);

HttpContext.User = genericPrincipal;

对于GenericIdentityIsAuthenticated 的值取决于 Name 属性,因此只要 GenericIdentity 有 Name,就认为它已通过身份验证。

在此示例中,我设置的是 HttpContext.User 而不是 Thread.CurrentPrincipal,以便您可以从 Request.IsAuthenticated 属性中获取 IsAuthenticated

一些额外的相关信息:

GenericIdentity Class

Principal and Identity Objects

Create GenericPrincipal and GenericIdentity Objects

Replacing a Principal Object

【讨论】:

  • 感谢您提供有趣的回答,我会进行更多研究,让大家知道它是否以及如何解决问题 :) 不幸的是,我没有足够的时间来奖励您,因为它明天结束
【解决方案5】:

在你的 startup.cs 文件中添加这个

app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Login"),

            SlidingExpiration = true,
            ExpireTimeSpan = TimeSpan.FromMinutes(40)


        });

【讨论】:

  • 谢谢,但这不适用于我的自定义身份验证
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-28
  • 1970-01-01
  • 1970-01-01
  • 2015-12-11
  • 1970-01-01
相关资源
最近更新 更多