. NET CORE 2.1- Как вернуть вызов, который не принадлежит DefaultChallengeScheme - PullRequest
5 голосов
/ 13 марта 2020

Итак, у меня есть сценарий, в котором я реализовал свою собственную схему аутентификации 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, подобный этому, как я могу вернуть схему Challenge, чтобы указать на мою внешнюю (facebook):

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

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

        return Challenge("facebook");
    }

Это также означало бы, что мой AuthenticateAsync не будет работать в этом случае, так как схема аутентификации по умолчанию указывает на JWT.

Как я могу добавить это в мой Challenge запрос и AuthenticateAsync метод?

Спасибо

1 Ответ

0 голосов
/ 16 марта 2020

Чтобы вернуть страницу входа для своего пользовательского поставщика удостоверений, необходимо вызвать метод 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
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...