【问题标题】:refresh token with bearer token authentication on asp.net vnext在 asp.net vnext 上使用不记名令牌身份验证刷新令牌
【发布时间】:2016-04-30 20:48:21
【问题描述】:

我有一个使用 asp.net vnext 的 angularJS 应用程序,它使用 JwtBearerAuthentication 进行身份验证。为了验证我使用AspNet.Security.OpenIdConnect.Server 的应用程序。当我登录时,我收到一个 json 响应,其中包含可用于授权请求的 access_token。我也想收到刷新令牌。这怎么可能?

Startup.cs

public void Configure(IApplicationBuilder app) {
    app.UseJwtBearerAuthentication(options => {
        options.AutomaticAuthenticate = true;
        options.AutomaticChallenge = true;
        options.TokenValidationParameters.ValidateAudience = false;
        options.Authority = Configuration.Get<string>("OAuth:Authority");
        options.ConfigurationManager = new ConfigurationManager<OpenIdConnectConfiguration>(
            metadataAddress: options.Authority + ".well-known/openid-configuration",
            configRetriever: new OpenIdConnectConfigurationRetriever(),
            docRetriever: new HttpDocumentRetriever() { RequireHttps = false });
    });

    app.UseOpenIdConnectServer(configuration => {
        configuration.Issuer = new Uri(Configuration.Get<string>("OpenId:Issuer"));
        configuration.AllowInsecureHttp = true;
        configuration.AuthorizationEndpointPath = PathString.Empty;
        configuration.AuthenticationScheme = OpenIdConnectServerDefaults.AuthenticationScheme;
        configuration.Provider = new AuthorizationProvider();
    });
}

AuthorizationProvider.cs

public class AuthorizationProvider : OpenIdConnectServerProvider {
    public override Task ValidateClientAuthentication(ValidateClientAuthenticationContext context) {
        context.Skipped();

        return Task.FromResult<object>(null);
    }

    public override Task GrantResourceOwnerCredentials(GrantResourceOwnerCredentialsContext context) {
        string username = context.UserName;
        string password = context.Password;

        UserManager<ApplicationUser> userManager = context.HttpContext.RequestServices.GetRequiredService<UserManager<ApplicationUser>>();
        ApplicationUser user = userManager.FindByNameAsync(username).Result;

        if (userManager.CheckPasswordAsync(user, password).Result) {
            ClaimsIdentity identity = new ClaimsIdentity(OpenIdConnectServerDefaults.AuthenticationScheme);
            identity.AddClaim(ClaimTypes.Name, username, "token id_token");

            List<string> roles = userManager.GetRolesAsync(user).Result.ToList();
            foreach (string role in roles) {
                identity.AddClaim(ClaimTypes.Role, role, "token id_token");
            }

            ClaimsPrincipal principal = new ClaimsPrincipal(identity);
            context.Validated(principal);
        } else {
            context.Rejected("invalid credentials");
        }

        return Task.FromResult<object>(null);
    }
}

AngularJS 登录代码

$http({
    method: 'POST',
    url: 'connect/token',
    headers: {
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
    },
    data: $.param({
        grant_type: 'password',
        username: email,
        password: password
    })
}).then(function (response) {
    if (response.status == 200) {
        var token = response.data.access_token;
        localStorage.setItem('token', token);
    }
});

【问题讨论】:

  • 附带说明,您不应禁用受众验证 (options.TokenValidationParameters.ValidateAudience = false)。相反,请考虑使用ticket.SetResources(new[] { "resource_server_1" }) 在访问令牌中设置正确的受众并在您的 JWT 不记名中间件选项中进行配置:options.Audience = "resource_server_1"
  • 你让我免于问另一个问题。我会试试看。谢谢

标签: asp.net angularjs asp.net-core jwt aspnet-contrib


【解决方案1】:

创建您的刷新令牌提供程序并将其包含到您的身份验证选项中。在这里您可以找到在类似环境中如何使用它的完整示例:

http://bitoftech.net/2014/07/16/enable-oauth-refresh-tokens-angularjs-app-using-asp-net-web-api-2-owin/

【讨论】:

    【解决方案2】:

    OAuthAuthorizationServerMiddleware 不同,ASOS 提供了对刷新令牌的内置支持:您不必为此创建自己的令牌提供程序。

    请注意,从 ASOS beta3(2015 年 10 月发布)开始,您现在必须请求并授予 offline_access 范围以检索刷新令牌,as recommended by the OpenID Connect specshttps://github.com/aspnet-contrib/AspNet.Security.OpenIdConnect.Server/issues/128

    您需要更新您的 GrantResourceOwnerCredentials 以允许 ASOS 向您的客户端应用程序发出刷新令牌:

    public override async Task GrantResourceOwnerCredentials(GrantResourceOwnerCredentialsContext context) {
        string username = context.UserName;
        string password = context.Password;
    
        UserManager<ApplicationUser> userManager = context.HttpContext.RequestServices.GetRequiredService<UserManager<ApplicationUser>>();
        ApplicationUser user = await userManager.FindByNameAsync(username);
    
        if (await userManager.CheckPasswordAsync(user, password)) {
            ClaimsIdentity identity = new ClaimsIdentity(
                context.Options.AuthenticationScheme);
    
            identity.AddClaim(ClaimTypes.Name, username,
                OpenIdConnectConstants.Destinations.AccessToken,
                OpenIdConnectConstants.Destinations.IdentityToken);
    
            foreach (string role in await userManager.GetRolesAsync(user)) {
                identity.AddClaim(ClaimTypes.Role, role,
                    OpenIdConnectConstants.Destinations.AccessToken,
                    OpenIdConnectConstants.Destinations.IdentityToken);
            }
    
            AuthenticationTicket ticket = new AuthenticationTicket(
                new ClaimsPrincipal(identity),
                new AuthenticationProperties(),
                context.Options.AuthenticationScheme);
    
            // Call SetResources with the list of resource servers
            // the access token should be issued for.
            ticket.SetResources("resource_server_1");
    
            // Only grant the "offline_access" scope
            // if it was requested by the client application:
            List<string> scopes = new List<string>();
            if (context.Request.HasScope("offline_access")) {
                scopes.Add("offline_access");
            }
    
            // Call SetScopes with the list of scopes you want to grant.
            ticket.SetScopes(scopes);
    
            context.Validate(ticket);
        } else {
            context.Reject("invalid credentials");
        }
    
        return Task.FromResult(0);
    }
    

    ...和你的Angular代码来指定scope参数:

    $http({
        method: 'POST',
        url: 'connect/token',
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
        },
        data: $.param({
            grant_type: 'password',
            username: email,
            password: password,
            scope: 'offline_access'
        })
    }).then(function (response) {
        if (response.status == 200) {
            var token = response.data.access_token;
            var refreshToken = response.data.refresh_token;
            localStorage.setItem('token', token);
            localStorage.setItem('refresh_token', refreshToken);
        }
    });
    

    要检索新的访问令牌,请使用refresh_token 授权:

    $http({
        method: 'POST',
        url: 'connect/token',
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
        },
        data: $.param({
            grant_type: 'refresh_token',
            refresh_token: refreshToken
        })
    }).then(function (response) {
        if (response.status == 200) {
            var token = response.data.access_token;
            localStorage.setItem('token', token);
        }
    });
    

    【讨论】:

    • 是否有任何关于在 EF 上持久化刷新令牌的示例?
    • 已更新以匹配 ASOS beta5 中使用的新名称(适用于 ASP.NET Core RC2)。
    猜你喜欢
    • 2017-11-08
    • 2020-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-29
    • 2020-02-16
    • 2021-03-05
    • 2020-08-05
    相关资源
    最近更新 更多