加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > asp.Net > 正文

asp.net-mvc – 实现MVC 5 IAuthenticationFilter

发布时间:2020-12-15 22:54:56 所属栏目:asp.Net 来源:网络整理
导读:执行OnAuthentication和OnAuthenticationChallenge之前,OnAuthentication和OnAuthenticationChallenge除了在执行操作之前运行,OnAuthenticationChallenge在执行操作之后但在处理动作结果之前运行. 看来,他们中的任何一个(OnAuthentication或OnAuthentication
执行OnAuthentication和OnAuthenticationChallenge之前,OnAuthentication和OnAuthenticationChallenge除了在执行操作之前运行,OnAuthenticationChallenge在执行操作之后但在处理动作结果之前运行.

看来,他们中的任何一个(OnAuthentication或OnAuthenticationChallenge)都可以执行身份验证所需的所有操作.为什么需要2种方法?

我的理解是OnAuthentication是我们将逻辑逻辑(或者这个逻辑应该在实际操作方法中),连接到数据存储并检查用户帐户. OnAuthenticationChallenge是我们重定向到登录页面的地方,如果不通过验证.它是否正确?为什么我不能重定向OnAuthentication并且不实现OnAuthenticationChallenge.我知道有一些我失踪的东西有人可以向我解释吗?

存储已验证用户的最佳做法是什么,以便后续请求不必连接到db再次检查用户?

请记住,我是ASP.NET MVC的新手.

解决方法

这些方法真的是为了不同的目的:

> IAuthenticationFilter.OnAuthentication应用于设置主体,主体是标识用户的对象.

您还可以像HttpUnauthorisedResult一样在此方法中设置结果(这将使您无法执行其他授权筛选器).虽然这是可能的,我喜欢分离不同的过滤器之间的关注.
> IAuthenticationFilter.OnAuthenticationChallenge用于在返回给用户之前向结果添加“挑战”.

>这个结果总是在结果返回给用户之前执行,这意味着它可以在不同请求的管道的不同点执行.请参阅下面的ControllerActionInvoker.InvokeAction的说明.
>使用此方法进行“授权”(例如检查用户是否登录或处于某个角色)可能是一个坏主意,因为它可能会在控制器操作代码之后被执行,因此您可能已经更改了db中的某些内容这被执行了!
>这个想法是这种方法可以用来对结果做出贡献,而不是执行关键的授权检查.例如,您可以使用它根据一些逻辑将HttpUnauthorisedResult转换为不同登录页面的重定向.或者您可以持有一些用户更改,将其重定向到另一个页面,您可以在其中请求其他确认/信息,并根据答案终于提交或丢弃这些更改.

> IAuthorizationFilter.OnAuthorization还应用于执行身份验证检查,例如检查用户是否登录或属于某个角色.

如果您检查ControllerActionInvoker.InvokeAction的源代码,您可以得到一个更好的主意.执行操作时将发生以下情况:

> IAuthenticationFilter.OnAuthentication为每个身份验证过滤器调用.如果在AuthenticationContext中更新了主体,则更新context.HttpContext.User和Thread.CurrentPrincipal.
>如果任何身份验证筛选器设置结果,例如设置404结果,则会为每个身份验证筛选器调用OnAuthenticationChallenge,这将允许在返回之前更改结果. (例如,您可以将其转换为重定向以登录).在挑战之后,结果将返回,而不进入步骤3.
>如果没有一个认证过滤器设置结果,则对于每个IAuthorizationFilter,它的OnAuthorization方法都将被执行.
>如步骤2所示,如果任何授权筛选器设置结果,则会为每个验证筛选器调用OnAuthenticationChallenge.在挑战之后,而不进入步骤3.
>如果没有一个授权过滤器设置结果,那么它将继续执行该操作(考虑到请求验证和任何操作过滤器)
>执行操作后,返回结果之前,将为每个身份验证过滤器调用OnAuthenticationChallenge

我已经将ControllerActionInvoker.InvokeAction的当前代码复制为参考,但可以使用上面的链接查看最新版本:

public virtual bool InvokeAction(ControllerContext controllerContext,string actionName)
{
    if (controllerContext == null)
    {
        throw new ArgumentNullException("controllerContext");
    }

    Contract.Assert(controllerContext.RouteData != null);
    if (String.IsNullOrEmpty(actionName) && !controllerContext.RouteData.HasDirectRouteMatch())
    {
        throw new ArgumentException(MvcResources.Common_NullOrEmpty,"actionName");
    }

    ControllerDescriptor controllerDescriptor = GetControllerDescriptor(controllerContext);
    ActionDescriptor actionDescriptor = FindAction(controllerContext,controllerDescriptor,actionName);

    if (actionDescriptor != null)
    {
        FilterInfo filterInfo = GetFilters(controllerContext,actionDescriptor);

        try
        {
            AuthenticationContext authenticationContext = InvokeAuthenticationFilters(controllerContext,filterInfo.AuthenticationFilters,actionDescriptor);

            if (authenticationContext.Result != null)
            {
                // An authentication filter signaled that we should short-circuit the request. Let all
                // authentication filters contribute to an action result (to combine authentication
                // challenges). Then,run this action result.
                AuthenticationChallengeContext challengeContext = InvokeAuthenticationFiltersChallenge(
                    controllerContext,actionDescriptor,authenticationContext.Result);
                InvokeActionResult(controllerContext,challengeContext.Result ?? authenticationContext.Result);
            }
            else
            {
                AuthorizationContext authorizationContext = InvokeAuthorizationFilters(controllerContext,filterInfo.AuthorizationFilters,actionDescriptor);
                if (authorizationContext.Result != null)
                {
                    // An authorization filter signaled that we should short-circuit the request. Let all
                    // authentication filters contribute to an action result (to combine authentication
                    // challenges). Then,run this action result.
                    AuthenticationChallengeContext challengeContext = InvokeAuthenticationFiltersChallenge(
                        controllerContext,authorizationContext.Result);
                    InvokeActionResult(controllerContext,challengeContext.Result ?? authorizationContext.Result);
                }
                else
                {
                    if (controllerContext.Controller.ValidateRequest)
                    {
                        ValidateRequest(controllerContext);
                    }

                    IDictionary<string,object> parameters = GetParameterValues(controllerContext,actionDescriptor);
                    ActionExecutedContext postActionContext = InvokeActionMethodWithFilters(controllerContext,filterInfo.ActionFilters,parameters);

                    // The action succeeded. Let all authentication filters contribute to an action result (to
                    // combine authentication challenges; some authentication filters need to do negotiation
                    // even on a successful result). Then,postActionContext.Result);
                    InvokeActionResultWithFilters(controllerContext,filterInfo.ResultFilters,challengeContext.Result ?? postActionContext.Result);
                }
            }
        }
        catch (ThreadAbortException)
        {
            // This type of exception occurs as a result of Response.Redirect(),but we special-case so that
            // the filters don't see this as an error.
            throw;
        }
        catch (Exception ex)
        {
            // something blew up,so execute the exception filters
            ExceptionContext exceptionContext = InvokeExceptionFilters(controllerContext,filterInfo.ExceptionFilters,ex);
            if (!exceptionContext.ExceptionHandled)
            {
                throw;
            }
            InvokeActionResult(controllerContext,exceptionContext.Result);
        }

        return true;
    }

    // notify controller that no method matched
    return false;
}

至于在设置主体时,在每次请求时都不会碰到数据库,可以使用某种服务器端缓存.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读