I have a web application that allow users to login and register using local authentication (with JWT Authentication scheme), and also allow users to login in their azure active directory account (using OpenIdConnect Scheme). I'm treating the logging with azure active directory as an external login, however, I keep getting null response when I'm trying to get the GetExternalLoginInfoAsync()
Below is my setup:
services.AddAuthentication(options =>
{
options.DefaultScheme = "JWT_OR_COOKIE";
options.DefaultChallengeScheme = "JWT_OR_COOKIE";
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
// for azure active directory
.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.Authority = config["authority"];
options.ClientId = config["clientId"];
options.ClientSecret = config["clientSecret"];
options.ResponseType = "code";
options.SaveTokens = true;
})
// for local login
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config["TokenKey"])),
ValidateIssuer = false,
ValidateAudience = false,
NameClaimType = "name",
RoleClaimType = "role"
};
options.RequireHttpsMetadata = env.IsProduction();
})
.AddPolicyScheme("JWT_OR_COOKIE", "JWT_OR_COOKIE", options =>
{
// runs on each request
options.ForwardDefaultSelector = context =>
{
// filter by auth type
string authorization = context.Request.Headers[HeaderNames.Authorization];
if (!string.IsNullOrEmpty(authorization) && authorization.StartsWith("Bearer "))
return JwtBearerDefaults.AuthenticationScheme;
// otherwise always check for cookie auth
return OpenIdConnectDefaults.AuthenticationScheme;
};
});
services.AddAuthorization(options =>
{
options.AddPolicy("RequireAdminRole", policy => policy.RequireRole("Admin"));
});
My controller:
[HttpGet("login")]
[AllowAnonymous]
public async Task<IActionResult> ExternalLogin([FromQuery] string returnUrl)
{
var scheme = OpenIdConnectDefaults.AuthenticationScheme;
var redirectUrl = Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl });
return Challenge(new AuthenticationProperties
{
RedirectUri = redirectUrl
}, scheme);
}
[HttpGet]
[AllowAnonymous]
public async Task<IActionResult> ExternalLoginCallback(string returnUrl)
{
var acccessToken = await HttpContext.GetTokenAsync("access_token"); // <== this works
var info = await _signInManager.GetExternalLoginInfoAsync(); // <=== this is null, and I don't know what I did wrong in here !!!
var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false);
if (result.Succeeded)
{
// update any authentication process
await _signInManager.UpdateExternalAuthenticationTokensAsync(info);
return LocalRedirect(returnUrl);
}
else
{
// do not have account yet
return Ok();
}
}
Please try by setting SignIn Scheme
to IdentityConstants.ExternalScheme
:
services.Configure<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme, options => options.SignInScheme = IdentityConstants.ExternalScheme);
And define cookie scheme to null
:
services.AddAuthentication()
.AddMicrosoftIdentityWebApp(Configuration, cookieScheme: null);
Something like:-
options => {
...
options.ClientId = config.ClientId;
options.TenantId = config.TenantId;
options.CallbackPath = config.CallbackPath;
options.SignInScheme = IdentityConstants.ExternalScheme;
options.SignOutScheme = IdentityConstants.ExternalScheme;
...
},
openIdConnectScheme: idp.LoginProvider,
cookieScheme: null
);
In some cases also try by upgrading asp.net core
to latest version or version campatible and check again.
References:
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.