.NET CORE 2.1-如何返回不属于 DefaultChallengeScheme 的挑战
Posted
技术标签:
【中文标题】.NET CORE 2.1-如何返回不属于 DefaultChallengeScheme 的挑战【英文标题】:.NET CORE 2.1- How to return a Challenge which does not belong to the DefaultChallengeScheme 【发布时间】:2020-06-25 10:33:39 【问题描述】:所以,我有一个场景,我实现了自己的JWT
身份验证方案,并且是我的Startup.cs
中的默认身份验证和质询方案:
services.AddAuthentication(x =>
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
)
.AddJwtBearer(x =>
//code ommitted for brevity
)
.AddCookie("cookie")
.AddOpenIdConnect("facbook", async options =>
options.ResponseType = "code";
options.SignInScheme = "cookie";
//code ommitted for brevity
);
正如您在上面看到的,我添加了AddOpenIdConnect
和AddCookie
用于我的外部身份验证。现在我的问题是,如果我有这样的Redirect
ActionMethod,如何返回挑战方案以指向我的外部方案(facebook):
[HttpGet]
public async Task<IActionResult> Redirect()
var result = await HttpContext.AuthenticateAsync();
if (result.Succeeded)
return RedirectToAction("Index");
return Challenge("facebook");
这也意味着我的AuthenticateAsync
在这种情况下将不起作用,因为默认身份验证方案指向JWT
。
如何将 this 添加到我的 Challenge
请求和 AuthenticateAsync
方法中?
谢谢
【问题讨论】:
看来你需要Authorize
属性[Authorize(AuthenticationSchemes = "facebook")]
:docs.microsoft.com/en-us/aspnet/core/security/authorization/…
【参考方案1】:
要返回自定义身份提供者的登录页面,您需要调用SignInManager.ConfigureExternalAuthenticationProperties() 方法。此方法允许您定义 redirectUrl 和提供者(您将提供者称为“facebook”)。
我是这样写的:
[Controller]
[Route("web/v2/[controller]")]
public class AccountController : Controller
private IAccountService accountService;
public AccountController(IAccountService accountService)
this.accountService = accountService;
// GET: web/Account/connect/provider
[AllowAnonymous]
[HttpGet("connect/medium/provider", Name = "web-v2-account-external-connect-challenge")]
public async Task<ActionResult> ExternalLogin([FromRoute]string medium, [FromRoute]string provider)
//var redirectUrl = Url.Action(nameof(ExternalLoginCallback), "Account", new medium, provider );
var redirectUrl = Url.RouteUrl("web-v2-account-external-connect-callback", new medium, provider );
var properties = await accountService.ConfigureExternalAuthenticationProperties(provider, redirectUrl);
return Challenge(properties, provider);
// GET: web/Account/connect/provider/callback
[HttpGet("connect/medium/provider/callback", Name = "web-v2-account-external-connect-callback")]
public async Task<ActionResult> ExternalLoginCallback([FromRoute]string medium, [FromRoute]string provider)
try
var login_result = await accountService.PerfromExternalLogin();
if (login_result.Status)
var model = new LoginResultVM
Status = true,
Medium = medium,
Platform = login_result.Platform
;
return View(model);
else
var model = new LoginResultVM
Status = false,
Medium = medium,
Platform = login_result.Platform,
Error = login_result.Error,
ErrorDescription = login_result.ErrorDescription
;
return View(model);
catch (OtherAccountException otherAccountEx)
var model = new LoginResultVM
Status = false,
Medium = medium,
Platform = provider,
Error = "Could not login",
ErrorDescription = otherAccountEx.Message
;
return View(model);
catch (Exception ex)
var model = new LoginResultVM
Status = false,
Medium = medium,
Platform = provider,
Error = "Could not login",
ErrorDescription = "There was an error with your social login"
;
return View(model);
虽然我的 AccountRepository 看起来像这样:
internal interface IAccountRepository
...
internal class AccountRepository : IAccountRepository
private MintPlayerContext mintplayer_context;
private UserManager<Entities.User> user_manager;
private SignInManager<Entities.User> signin_manager;
private JwtIssuerOptions jwtIssuerOptions;
public AccountRepository(UserManager<Entities.User> user_manager, SignInManager<Entities.User> signin_manager, MintPlayerContext mintplayer_context, IOptions<JwtIssuerOptions> jwtIssuerOptions)
this.user_manager = user_manager;
this.signin_manager = signin_manager;
this.mintplayer_context = mintplayer_context;
this.jwtIssuerOptions = jwtIssuerOptions.Value;
public async Task<Tuple<User, string>> Register(User user, string password)
...
public async Task<LoginResult> LocalLogin(string email, string password, bool createCookie)
...
public async Task<IEnumerable<AuthenticationScheme>> GetExternalLoginProviders()
var providers = await signin_manager.GetExternalAuthenticationSchemesAsync();
return providers.ToList();
public Task<AuthenticationProperties> ConfigureExternalAuthenticationProperties(string provider, string redirectUrl)
var properties = signin_manager.ConfigureExternalAuthenticationProperties(provider, redirectUrl);
return Task.FromResult(properties);
public async Task<LoginResult> PerfromExternalLogin()
var info = await signin_manager.GetExternalLoginInfoAsync();
if (info == null)
throw new UnauthorizedAccessException();
var user = await user_manager.FindByLoginAsync(info.LoginProvider, info.ProviderKey);
if (user == null)
string username = info.Principal.FindFirstValue(ClaimTypes.Name);
string email = info.Principal.FindFirstValue(ClaimTypes.Email);
var new_user = new Entities.User
UserName = username,
Email = email,
PictureUrl = null
;
var id_result = await user_manager.CreateAsync(new_user);
if (id_result.Succeeded)
user = new_user;
else
// User creation failed, probably because the email address is already present in the database
if (id_result.Errors.Any(e => e.Code == "DuplicateEmail"))
var existing = await user_manager.FindByEmailAsync(email);
var existing_logins = await user_manager.GetLoginsAsync(existing);
if (existing_logins.Any())
throw new OtherAccountException(existing_logins);
else
throw new Exception("Could not create account from social profile");
else
throw new Exception("Could not create account from social profile");
await user_manager.AddLoginAsync(user, new UserLoginInfo(info.LoginProvider, info.ProviderKey, info.ProviderDisplayName));
await signin_manager.SignInAsync(user, true);
return new LoginResult
Status = true,
Platform = info.LoginProvider,
User = ToDto(user)
;
public async Task<IEnumerable<UserLoginInfo>> GetExternalLogins(ClaimsPrincipal userProperty)
...
public async Task AddExternalLogin(ClaimsPrincipal userProperty)
...
public async Task RemoveExternalLogin(ClaimsPrincipal userProperty, string provider)
...
public async Task<User> GetCurrentUser(ClaimsPrincipal userProperty)
var user = await user_manager.GetUserAsync(userProperty);
return ToDto(user);
public async Task Logout()
await signin_manager.SignOutAsync();
#region Helper methods
private string CreateToken(Entities.User user)
...
#endregion
#region Conversion methods
internal static Entities.User ToEntity(User user)
...
internal static User ToDto(Entities.User user)
...
#endregion
【讨论】:
以上是关于.NET CORE 2.1-如何返回不属于 DefaultChallengeScheme 的挑战的主要内容,如果未能解决你的问题,请参考以下文章
.Net Core 2.1 过期的 JWT 令牌响应 [发布与获取]
IFormFile 在 asp.net core 2.1 中总是返回 null
ASP.NET Core 2.1 Razor 页面返回带有模型的页面
JQuery 在 ASP.NET Core 2.1 中返回“未定义”值