hi
Have you checked the source that I shared?
I have a multi tenant application. I want to enable both okta and auth0 for each tenant. As asp.net zero support only one authentication for a single tenant, I understand I need to customize the code.
You can add multiple OpenIdConnect as authentication providers. The string provider will be Auth0 or Okta
authenticationBuilder.AddOpenIdConnect("Auth0", options => ...
authenticationBuilder.AddOpenIdConnect("Okta", options =>
public ActionResult ExternalLogin(string provider, string returnUrl, string ss = "")
{
using (_googleOptions.As<TenantBasedOpenIdConnectOptions>().Change(new OpenIdConnectOptions()))
{
// Change the client id and secret to current OpenIdConnectOptions
var redirectUrl = Url.Action(
"ExternalLoginCallback",
"Account",
new
{
ReturnUrl = returnUrl,
authSchema = provider,
ss = ss
});
var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl);
return Challenge(properties, provider);
}
}
https://github.com/aspnetzero/aspnet-zero-core/commit/7541fa92769e0ff340ccfb9424a5f58c62ca1c08 https://support.aspnetzero.com/QA/Questions/12204/How-can-I-enable-both-okta-and-auth0-for-a-tenant-using-openid#answer-0665e369-ea30-363f-9ae6-3a15cec05d04
Hi kan software
Can you share a project to reproduce?
In this way, we can quickly troubleshoot and solve the problem.
If UserLoginInfo
exists under a tenant, you must switch to this tenant.
hi
I have configured okta for a tenant using openid from its settings page. Now when I am calling this API it gives me Unknown external auth provider error.
Does UserLoginInfo(model.AuthProvider, externalUser.ProviderKey, model.AuthProvider)
exist on your database?
it generally coming from externalLoginInfo = await _signInManager.GetExternalLoginInfoAsync();
hi
These classes allow you to change the options at runtime. They get tenant settings values( from the database).
In fact, you can add multiple OpenIdConnect
as authentication providers.
authenticationBuilder.AddOpenIdConnect("Auth0", options => ...
authenticationBuilder.AddOpenIdConnect("Okta", options =>
The name
is the Auth0
or Okta
hi @uxabp,
Can you try the code below?
//Add these lines to your ef core module Initialize method.
var adapter = new AbpDevExtremeAsyncAdapter();
CustomAsyncAdapters.RegisterAdapter(typeof(AbpEntityQueryProvider), adapter);
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using DevExtreme.AspNet.Data.Async;
namespace Abp.EntityFrameworkCore;
public class AbpDevExtremeAsyncAdapter : IAsyncAdapter
{
private readonly MethodInfo _countAsyncMethod;
private readonly MethodInfo _toListAsyncMethod;
public AbpDevExtremeAsyncAdapter()
{
var extensionsType = Type.GetType("Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions, Microsoft.EntityFrameworkCore");
_countAsyncMethod = FindQueryExtensionMethod(extensionsType, "CountAsync");
_toListAsyncMethod = FindQueryExtensionMethod(extensionsType, "ToListAsync");
}
public Task<int> CountAsync(IQueryProvider provider, Expression expr, CancellationToken cancellationToken)
{
return InvokeCountAsync(_countAsyncMethod, provider, expr, cancellationToken);
}
public Task<IEnumerable<T>> ToEnumerableAsync<T>(IQueryProvider provider, Expression expr, CancellationToken cancellationToken)
{
return InvokeToListAsync<T>(_toListAsyncMethod, provider, expr, cancellationToken);
}
static MethodInfo FindQueryExtensionMethod(Type extensionsType, string name)
{
return extensionsType.GetMethods().First(m =>
{
if (!m.IsGenericMethod || m.Name != name)
{
return false;
}
var parameters = m.GetParameters();
return parameters.Length == 2 && parameters[1].ParameterType == typeof(CancellationToken);
});
}
static Task<int> InvokeCountAsync(MethodInfo method, IQueryProvider provider, Expression expr, CancellationToken cancellationToken)
{
var countArgument = ((MethodCallExpression)expr).Arguments[0];
var query = provider.CreateQuery(countArgument);
return (Task<int>)InvokeQueryExtensionMethod(method, query.ElementType, query, cancellationToken);
}
static async Task<IEnumerable<T>> InvokeToListAsync<T>(MethodInfo method, IQueryProvider provider, Expression expr, CancellationToken cancellationToken)
{
return await (Task<List<T>>)InvokeQueryExtensionMethod(method, typeof(T), provider.CreateQuery(expr), cancellationToken);
}
static object InvokeQueryExtensionMethod(MethodInfo method, Type elementType, IQueryable query, CancellationToken cancellationToken)
{
return method.MakeGenericMethod(elementType).Invoke(null, new object[] { query, cancellationToken });
}
}
hi
can you explain why the method should be virtual for it to work?
Castle Windsor's interceptor can only intercept:
Because application services will use classes as MVC controllers, virtual methods are needed.
I wasn't expecting virtual, cause for AbpAuthorize we do not need to make it virtual. Can you elaborate on that?
Abp also uses MVC filters to intercept method calls. It does not require virtual methods. It is only suitable for controllers or Pages.
https://github.com/aspnetboilerplate/aspnetboilerplate/blob/dev/src/Abp.AspNetCore/AspNetCore/Mvc/Authorization/AbpAuthorizationFilter.cs#L54