asp.net 核心应用程序 (MVC) 中的 auth0 授权
auth0 authorisation in asp.net core app (MVC)
我正在尝试让 Auth0 在我的 MVC 应用程序中工作。
虽然身份验证有效,但我似乎无法获得授权。
我已经学习了这个教程:https://auth0.com/docs/quickstart/webapp/aspnet-core
我的代码:
public static IServiceCollection AddAuth0(this IServiceCollection services, IConfiguration configuration)
{
var auth0Options = configuration.GetSection(nameof(Auth0Config))
.Get<Auth0Config>();
services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
// options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
// options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}) //do i need this for access_token?
// .AddJwtBearer(options =>
// {
// options.Authority = auth0Options.Domain;
// options.Audience = auth0Options.ApiIdentifier;
//
// options.SaveToken = true;
// options.RequireHttpsMetadata = false;
// })
.AddCookie()
.AddOpenIdConnect(Auth0Constants.Auth0Scheme, options =>
{
options.Authority = $"https://{auth0Options.Domain}";
options.ClientId = auth0Options.ClientId;
options.ClientSecret = auth0Options.ClientSecret;
options.ResponseType = Auth0Constants.ResponseTypeCode;
options.SaveToken = true;
options.Scope.Clear();
options.Scope.Add(Auth0Constants.Auth0Scope.openid.ToString());
options.Scope.Add(Auth0Constants.Auth0Scope.email.ToString());
options.Scope.Add(Auth0Constants.Auth0Scope.profile.ToString());
options.Scope.Add("read:cars");
options.CallbackPath = new PathString("/callback");
options.ClaimsIssuer = Auth0Constants.Auth0Scheme;
options.Events = new OpenIdConnectEvents
{
OnRedirectToIdentityProviderForSignOut = context => OnRedirectToIdentityProviderForSignOut(context, auth0Options),
OnRedirectToIdentityProvider = context => OnRedirectToIdentityProvider(context, auth0Options)
};
});
services.AddAuthorization(options =>
{
options.AddPolicy("read:cars", policy => policy.Requirements.Add(new HasScopeRequirement("read:cars", auth0Options.Domain)));
});
services.AddSingleton<IAuthorizationHandler, HasScopeHandler>();
return services;
}
private static Task OnRedirectToIdentityProvider(RedirectContext context, Auth0Config config)
{
context.ProtocolMessage.SetParameter("audience", config.ApiIdentifier);
return Task.CompletedTask;
}
private static Task OnRedirectToIdentityProviderForSignOut(RedirectContext context, Auth0Config auth0Options)
{
var logoutUri = $"https://{auth0Options.Domain}/v2/logout?client_id={auth0Options.ClientId}";
var postLogoutUri = context.Properties.RedirectUri;
if (!string.IsNullOrEmpty(postLogoutUri))
{
if (postLogoutUri.StartsWith("/"))
{
var request = context.Request;
postLogoutUri = request.Scheme + "://" + request.Host + request.PathBase + postLogoutUri;
}
logoutUri += $"&returnTo={Uri.EscapeDataString(postLogoutUri)}";
}
context.Response.Redirect(logoutUri);
context.HandleResponse();
return Task.CompletedTask;
}
当我查看我的 charles 会话时,我确实看到令牌中返回了正确的范围和权限:
"scope": "openid profile email read:cars",
"permissions": [
"read:cars"
]
但是例如,我无法像他们说的那样得到 access_token
:
var accessToken = await HttpContext.GetTokenAsync("access_token");
这个returns空;它也不在索赔中。
在我的一个控制器上,我有:[Authorize("read:cars")]
我的访问被拒绝,我是否删除该权限并仅使用授权,那么我很好。
检查作用域是否存在:
public class HasScopeRequirement : IAuthorizationRequirement
{
public string Issuer { get; }
public string Scope { get; }
public HasScopeRequirement(string scope, string issuer)
{
Scope = scope;
Issuer = issuer;
}
}
public class HasScopeHandler : AuthorizationHandler<HasScopeRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, HasScopeRequirement requirement)
{
// If user does not have the scope claim, get out of here
if (!context.User.HasClaim(c => c.Type == "scope" && c.Issuer == requirement.Issuer))
return Task.CompletedTask;
// Split the scopes string into an array
var scopes = context.User.FindFirst(c => c.Type == "scope" && c.Issuer == requirement.Issuer).Value.Split(' ');
// Succeed if the scope array contains the required scope
if (scopes.Any(s => s == requirement.Scope))
context.Succeed(requirement);
return Task.CompletedTask;
}
}
但我想这不是我的问题,我认为这是我 access_token 的问题,我什至无法阅读。所以我想我错过了一些东西。是因为 DefaultAuthenticationScheme/ChallengeScheme 还是 ...?
感谢柯克!
修正了与我原来的想法有点不同的问题;现在我正在使用角色。
在 auth0 中我有用户,并为他们分配所需的角色;
一般来说:
function (user, context, callback) {
context.idToken['http://schemas.microsoft.com/ws/2008/06/identity/claims/roles'] = context.authorization.roles;
callback(null, user, context);
}
我使用 http://schemas.microsoft.com/ws/2008/06/identity/claims/roles
作为默认声明,因为 .net 核心默认映射到那个。
在我的设置中我添加了:
options.TokenValidationParameters= new TokenValidationParameters
{
RoleClaimType = "http://schemas.microsoft.com/ws/2008/06/identity/claims/roles"
};
现在我可以在我的控制器上使用授权属性
澄清一下;我只有一个 webapp.If 我会去另一个 API 然后我将不得不使用 access_token 关闭课程。
我正在尝试让 Auth0 在我的 MVC 应用程序中工作。 虽然身份验证有效,但我似乎无法获得授权。
我已经学习了这个教程:https://auth0.com/docs/quickstart/webapp/aspnet-core
我的代码:
public static IServiceCollection AddAuth0(this IServiceCollection services, IConfiguration configuration)
{
var auth0Options = configuration.GetSection(nameof(Auth0Config))
.Get<Auth0Config>();
services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
// options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
// options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}) //do i need this for access_token?
// .AddJwtBearer(options =>
// {
// options.Authority = auth0Options.Domain;
// options.Audience = auth0Options.ApiIdentifier;
//
// options.SaveToken = true;
// options.RequireHttpsMetadata = false;
// })
.AddCookie()
.AddOpenIdConnect(Auth0Constants.Auth0Scheme, options =>
{
options.Authority = $"https://{auth0Options.Domain}";
options.ClientId = auth0Options.ClientId;
options.ClientSecret = auth0Options.ClientSecret;
options.ResponseType = Auth0Constants.ResponseTypeCode;
options.SaveToken = true;
options.Scope.Clear();
options.Scope.Add(Auth0Constants.Auth0Scope.openid.ToString());
options.Scope.Add(Auth0Constants.Auth0Scope.email.ToString());
options.Scope.Add(Auth0Constants.Auth0Scope.profile.ToString());
options.Scope.Add("read:cars");
options.CallbackPath = new PathString("/callback");
options.ClaimsIssuer = Auth0Constants.Auth0Scheme;
options.Events = new OpenIdConnectEvents
{
OnRedirectToIdentityProviderForSignOut = context => OnRedirectToIdentityProviderForSignOut(context, auth0Options),
OnRedirectToIdentityProvider = context => OnRedirectToIdentityProvider(context, auth0Options)
};
});
services.AddAuthorization(options =>
{
options.AddPolicy("read:cars", policy => policy.Requirements.Add(new HasScopeRequirement("read:cars", auth0Options.Domain)));
});
services.AddSingleton<IAuthorizationHandler, HasScopeHandler>();
return services;
}
private static Task OnRedirectToIdentityProvider(RedirectContext context, Auth0Config config)
{
context.ProtocolMessage.SetParameter("audience", config.ApiIdentifier);
return Task.CompletedTask;
}
private static Task OnRedirectToIdentityProviderForSignOut(RedirectContext context, Auth0Config auth0Options)
{
var logoutUri = $"https://{auth0Options.Domain}/v2/logout?client_id={auth0Options.ClientId}";
var postLogoutUri = context.Properties.RedirectUri;
if (!string.IsNullOrEmpty(postLogoutUri))
{
if (postLogoutUri.StartsWith("/"))
{
var request = context.Request;
postLogoutUri = request.Scheme + "://" + request.Host + request.PathBase + postLogoutUri;
}
logoutUri += $"&returnTo={Uri.EscapeDataString(postLogoutUri)}";
}
context.Response.Redirect(logoutUri);
context.HandleResponse();
return Task.CompletedTask;
}
当我查看我的 charles 会话时,我确实看到令牌中返回了正确的范围和权限:
"scope": "openid profile email read:cars",
"permissions": [
"read:cars"
]
但是例如,我无法像他们说的那样得到 access_token
:
var accessToken = await HttpContext.GetTokenAsync("access_token");
这个returns空;它也不在索赔中。
在我的一个控制器上,我有:[Authorize("read:cars")]
我的访问被拒绝,我是否删除该权限并仅使用授权,那么我很好。
检查作用域是否存在:
public class HasScopeRequirement : IAuthorizationRequirement
{
public string Issuer { get; }
public string Scope { get; }
public HasScopeRequirement(string scope, string issuer)
{
Scope = scope;
Issuer = issuer;
}
}
public class HasScopeHandler : AuthorizationHandler<HasScopeRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, HasScopeRequirement requirement)
{
// If user does not have the scope claim, get out of here
if (!context.User.HasClaim(c => c.Type == "scope" && c.Issuer == requirement.Issuer))
return Task.CompletedTask;
// Split the scopes string into an array
var scopes = context.User.FindFirst(c => c.Type == "scope" && c.Issuer == requirement.Issuer).Value.Split(' ');
// Succeed if the scope array contains the required scope
if (scopes.Any(s => s == requirement.Scope))
context.Succeed(requirement);
return Task.CompletedTask;
}
}
但我想这不是我的问题,我认为这是我 access_token 的问题,我什至无法阅读。所以我想我错过了一些东西。是因为 DefaultAuthenticationScheme/ChallengeScheme 还是 ...?
感谢柯克!
修正了与我原来的想法有点不同的问题;现在我正在使用角色。
在 auth0 中我有用户,并为他们分配所需的角色;
一般来说:
function (user, context, callback) {
context.idToken['http://schemas.microsoft.com/ws/2008/06/identity/claims/roles'] = context.authorization.roles;
callback(null, user, context);
}
我使用 http://schemas.microsoft.com/ws/2008/06/identity/claims/roles
作为默认声明,因为 .net 核心默认映射到那个。
在我的设置中我添加了:
options.TokenValidationParameters= new TokenValidationParameters
{
RoleClaimType = "http://schemas.microsoft.com/ws/2008/06/identity/claims/roles"
};
现在我可以在我的控制器上使用授权属性
澄清一下;我只有一个 webapp.If 我会去另一个 API 然后我将不得不使用 access_token 关闭课程。