总是得到“此请求的授权已被拒绝”。在身份 2 中使用不记名令牌?

Posted

技术标签:

【中文标题】总是得到“此请求的授权已被拒绝”。在身份 2 中使用不记名令牌?【英文标题】:Always get "Authorization has been denied for this request." using Bearer tokens in Identity 2? 【发布时间】:2015-09-17 15:59:51 【问题描述】:

使用邮递员我可以请求一个令牌,这里是:


    "access_token": "N1FL606bmDkZyLplpkLAihaviMQhB042z-rhY262M_W5nSWIv8fDOQiYkEn6GCuDnrxpdOWBS7lpxlBazHYlwnP1RvpDFED1i_ml89QNspyGOWB6TcMkT1MmfUAZ617k9MNvl5UJh2jKzUwvDDeXMURG9tEtmE3UX2L2D-1VA9kqYOzOB1UYbpMAfdTi84jsbR0lhLkNkReQ5fqg4B3IFbbWNGWu5ONb1uuf00ixL-BIMqSvEaNn58_zCyAVFWVzcH2tayYTGT5p_AItKfYiWaYHKC0pDoZ_OBdlpB7Odc7ScwjwFM5vtpBZE81rpk8yjXnrTEk_j9n0eiloJnpWwA",
    "token_type": "bearer",
    "expires_in": 899,
    "refresh_token": "60da311d10f043b892c703c7fb7ab061",
    "as:client_id": "Erp",
    "userName": "bbauer",
    ".issued": "Tue, 30 Jun 2015 17:56:10 GMT",
    ".expires": "Tue, 30 Jun 2015 18:11:10 GMT"

我还可以从不受保护的资源中获取信息,如下所示: http://localhost:60689/api/Accounts/User/bbauer


    "url": "http://localhost:60689/api/accounts/user/31",
    "id": 31,
    "userName": "bbauer",
    "fullName": "Brian Bauer",
    "email": null,
    "emailConfirmed": false,
    "roles": [
        "Administrator"
    ],
    "claims": []

从中我看到用户是“管理员”角色。当我尝试获取受保护的资源时,我总是会返回:“此请求的授权已被拒绝。”

这是控制器中的方法:

[Authorize(Roles = "Administrator")]
[Route("user/id:int", Name = "GetUserById")]
public async Task<IHttpActionResult> GetUser(int id)

    var user = await AppUserManager.FindByIdAsync(id);

    if (user != null)
    
        return Ok(TheModelFactory.Create(user));
    

    return NotFound();

这是我在邮递员中的设置: http://localhost:60689/api/Accounts/User/31Content-Type: application/json接受: application/json授权: Bearer N1FL606bmDkZyLplpkLAihaviMQhB042z- rhY262M_W5nSWIv8fDOQiYkEn6GCuDnrxpdOWBS7lpxlBazHYlwnP1RvpDFED1i_ml89QNspyGOWB6TcMkT1MmfUAZ617k9MNvl5UJh2jKzUwvDDeXMURG9tEtmE3UX2L2D-1VA9kqYOzOB1UYbpMAfdTi84jsbR0lhLkNkReQ5fqg4B3IFbbWNGWu5ONb1uuf00ixL-BIMqSvEaNn58_zCyAVFWVzcH2tayYTGT5p_AItKfYiWaYHKC0pDoZ_OBdlpB7Odc7ScwjwFM5vtpBZE81rpk8yjXnrTEk_j9n0eiloJnpWwA

我可以使用 fiddler 来验证正在发送的授权标头。另一件需要注意的事情是,当我传入 access_token 以获取未受保护的 /user/username 资源时,我可以中断代码并使用以下设置查看 ClaimsPrincipal:AuthenticationType: BearerIsAuthenticated: true姓名: bbauer

但是,如果我测试 User.IsInRole("Administrator") 它总是错误的。为什么是假的? AspNetUserRole 表有条目,当我获取用户时,我看到他的一个角色是“管理员”......我在上帝的绿色地球上错过了什么?

如果有帮助,这是我的 Startup 课程:

public class Startup

    public static OAuthAuthorizationServerOptions OAuthServerOptions  get; private set; 
    public static OAuthBearerAuthenticationOptions OAuthBearerOptions  get; private set; 
    public static string PublicClientId  get; private set; 

    public void Configuration(IAppBuilder app)
    
        var httpConfig = new HttpConfiguration();

        ConfigureOAuth(app);

        WebApiConfig.Register(httpConfig);

        app.UseCors(CorsOptions.AllowAll);
        app.UseWebApi(httpConfig);
    

    public void ConfigureOAuth(IAppBuilder app)
    
        // Configure the db context and user manager to use a single instance per request
        app.CreatePerOwinContext(ApplicationDbContext.Create);
        app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
        app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);

        PublicClientId = "self";
        OAuthServerOptions = new OAuthAuthorizationServerOptions
        
            AllowInsecureHttp = true,
            TokenEndpointPath = new PathString("/Token"),
            AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(15),
            Provider = new SimpleAuthorizationServerProvider(PublicClientId),
            RefreshTokenProvider = new SimpleRefreshTokenProvider(),
        ;

        app.UseOAuthAuthorizationServer(OAuthServerOptions);

        OAuthBearerOptions = new OAuthBearerAuthenticationOptions();
        app.UseOAuthBearerAuthentication(OAuthBearerOptions);
    

【问题讨论】:

【参考方案1】:

事实证明,我需要在 SimpleAuthorizationServerProvider 的 GrantResourceOwnerCredentials 方法中向我的 ClaimsIdentity 添加角色。这是代码(见注释部分):

public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)

    var allowedOrigin = context.OwinContext.Get<string>("as:clientAllowedOrigin") ?? "*";

    context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[]  allowedOrigin );

    var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();

    ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);

    if (user == null)
    
        context.SetError("invalid_grant", "The user name or password is incorrect.");
        return;
    

    var identity = new ClaimsIdentity(context.Options.AuthenticationType);
    identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName));
    identity.AddClaim(new Claim("sub", context.UserName));

    //this loop is where the roles are added as claims
    foreach (var role in userManager.GetRoles(user.Id))
    
        identity.AddClaim(new Claim(ClaimTypes.Role, role));
    

    var props = new AuthenticationProperties(new Dictionary<string, string>
    
        
            "as:client_id", context.ClientId ?? string.Empty
        ,
        
            "userName", context.UserName
        
    );

    var ticket = new AuthenticationTicket(identity, props);
    context.Validated(ticket);

【讨论】:

以上是关于总是得到“此请求的授权已被拒绝”。在身份 2 中使用不记名令牌?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 web api Authentication Failed 场景中获取详细错误而不是“消息”:“此请求的授权已被拒绝。”?

此请求的授权已被拒绝 - 桌面到 ASP.NET Web API

自托管 owin 应用程序中的混合授权(Windows NTLM 和匿名)不起作用 - “此请求的授权已被拒绝”

在接收访问令牌时使用 amazon application load balancer 和 django oidc provider 对用户进行身份验证时总是得到 401 或 500

为啥基本身份验证总是使用 restTemplate 给出错误 403?

Laravel 5.3 + Passport:总是未经身份验证的错误