.NET CORE 2.1- 如何返回不属于 DefaultChallengeScheme 的挑战

Rah*_*rma 6 c# asp.net-core

所以,我有一个场景,我已经实现了自己的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
});
Run Code Online (Sandbox Code Playgroud)

正如你可以看到上面我已经加入AddOpenIdConnectAddCookie我的外部认证。现在我的问题是,如果我有这样的RedirectActionMethod,如何返回挑战方案以指向我的外部方案(facebook):

    [HttpGet]
    public async Task<IActionResult> Redirect()
    {
        var result = await HttpContext.AuthenticateAsync();

        if (result.Succeeded)
        {
            return RedirectToAction("Index");
        }

        return Challenge("facebook");
    }
Run Code Online (Sandbox Code Playgroud)

这也意味着 myAuthenticateAsync在这种情况下不起作用,因为默认身份验证方案指向JWT.

如何将 this 添加到我的Challenge请求和AuthenticateAsync方法中?

谢谢

Pie*_*jan 0

要返回自定义身份提供程序的登录页面,您需要调用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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

虽然我的 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
}
Run Code Online (Sandbox Code Playgroud)