可以';设置Thread和HttpContext主体后,不能访问或授权ASP.Net Web API

本文关键字:访问 不能 授权 ASP API Web Net 设置 Thread 主体 HttpContext | 更新日期: 2023-09-27 17:59:38

对授权和身份验证很陌生,所以我可能错过了一些重要的步骤。。。只需查看大量参考资料、指南和教程。

我可能需要在我的WebApiConfig中做些什么?

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.MapHttpAttributeRoutes();
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
    }
}

或者可能在我的Global.asax:中

public class WebApiApplication : System.Web.HttpApplication
{
    private const string RootDocument = "/index.html";
    protected void Application_Start()
    {
        GlobalConfiguration.Configure(WebApiConfig.Register);
    }
    protected void Application_BeginRequest(Object sender, EventArgs e)
    {
        // Stuff to redirect to index.html unless it's an api url
    }
}

这是一个ASP.NETWeb API项目,目标是.NETFramework4.5.2,带有Angular2前端,我在前端不手动执行任何操作,也许我需要这样做?我的本地存储、会话存储和Cookie在浏览器上都是空的。

我正在访问的SQL Server有一个非常简单的用户登录方法,它返回一个角色和userId,我在这里的存储库中调用它:

    public static DbUser Logon(AuthUser user)
    {
        var parameters = new List<SqlParameter>();
        {
            // Add parameters, get the DbUser (contains role and userId), and return the DbUser
        }
    }

登录前端使用Angular 2构建,并在提交到以下API方法时使用用户名和密码进行HttpPost调用,创建标识和主体,并设置Thread和HttpContext:

    // POST api/<controller>
    [HttpPost]
    public TokenUser Post(AuthUser user)
    {
        var dbUser = DBAccess.Repository.User.Logon(user);
        var identity = new ClaimsIdentity();
        identity.AddClaim(new Claim(ClaimTypes.Name, "CwRole"));
        identity.AddClaim(new Claim(ClaimTypes.Role, dbUser.AccessLevel));
        identity.AddClaim(new Claim(ClaimTypes.UserData, dbUser.ID.ToString()));
        var principal = new ClaimsPrincipal(identity);
        Thread.CurrentPrincipal = principal;
        if (HttpContext.Current != null)
            HttpContext.Current.User = principal;
        // Other stuff and a return statement =>
        // Note I'm not actually doing anything manually with the token on the front end
        // which may be why I'm not seeing it in the debugger's Resources tab...
    }

当我浏览这些代码时,我可以清楚地看到Thread.CurrentPrincipal和HttpContext.Current.User都被填充了,这看起来很合适。

但是,如果我用[Authorize]属性修饰一个操作,无论是否登录,我都无法访问它。

        // Works fine
        public IEnumerable<ItemGroup> Get()
        {
            return DBAccess.Repository.Item.GetItemGroups();
        }
        // Responds with 401 (Unauthorized) no matter what
        [Authorize]
        public IEnumerable<RequestItem> Get()
        {
            return DBAccess.Repository.Item.GetRequestItems();
        }

因此,我创建了这些方法,在上述登录过程后通过浏览器url访问它们,并逐步完成,结果发现用户从未被实际设置(声明都是空的,等等…)

public class AuthController : ApiController
{
    public bool Get()
    {
        // Stepping through, looks like User.Identity is not even set...
        var authenticated = User.Identity.IsAuthenticated;
        return authenticated;
    }
    public bool Get(string role)
    {
        // As a matter of fact, User doesn't have any claims or anything...
        var user = User;
        return user != null && user.IsInRole(role);
    }
}

那么,在设置主体之后,我缺少了什么步骤来使其可访问呢?我是否需要使用WebApi内置的"用户"方法以外的其他方法访问它,或者在我的配置上设置一些内容,或者在前端手动执行一些操作?

可以';设置Thread和HttpContext主体后,不能访问或授权ASP.Net Web API

您正在使用Claim身份验证,因此成功进行身份验证后,您将收到一个令牌。因此,为了为后续/后续的WebApi请求持久化令牌,您必须使用以下方法之一来持久化

  1. 您必须将身份验证详细信息设置为Cookie,浏览器将自动将其附加到所有后续请求
  2. 您可以将令牌保存在浏览器的本地存储中,用于以下请求-您必须将Claims Bearer令牌附加到请求标头中[用于身份验证]

选项1:

设置身份验证cookie

FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, username, DateTime.Now, DateTime.Now.AddMinutes(30), true, userData);
         string encTicket = FormsAuthentication.Encrypt(ticket);
         HttpCookie faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
         Response.Cookies.Add(faCookie);

访问cookie以在后续请求中进行身份验证。

HttpCookie authCookie = Request.Cookies[
             FormsAuthentication.FormsCookieName];
    if(authCookie != null)
    {
        //Extract the forms authentication cookie
        FormsAuthenticationTicket authTicket = 
               FormsAuthentication.Decrypt(authCookie.Value);
        // Create an Identity object
        //CustomIdentity implements System.Web.Security.IIdentity
        CustomIdentity id = GetUserIdentity(authTicket.Name);
        //CustomPrincipal implements System.Web.Security.IPrincipal
        CustomPrincipal newUser = new CustomPrincipal();
        Context.User = newUser;
    }

选项2:

您可以获取令牌并将其保存到浏览器本地存储,当您使用Authorize关键字向任何API发出请求时,请确保将Bearer令牌添加到请求头中。

像这样的

var authData = localStorageService.get('authorizationData');
        if (authData) {
            config.headers.Authorization = 'Bearer ' + authData.token;
        }

下面的文章解释了基于令牌的身份验证,并提供了Angular JS的代码示例,但请看一下http://bitoftech.net/2015/02/16/implement-oauth-json-web-tokens-authentication-in-asp-net-web-api-and-identity-2/

最后,

对于服务器端的验证,您可以编写一个自定义的authorize而不是默认的authorize来验证令牌并相应地设置标识。

OnAuthorization事件发生在管道的早期。任何类型的ActionFilter都会在它之后运行。正如我所猜测的,您在操作过滤器中或在OnAuthorization事件之后执行的某个地方编写了身份验证代码(第一个片段)。

您应该考虑将该代码传输到,例如,此事件(在global.asax.cs中)

Application_PostAuthenticateRequest(Object sender, EventArgs e)

更优雅的方法是实现自定义AuthorizeAttribute,从Request获取用户信息并设置Principals。