Yes, It have the Login Failed Exception information.
We found a workaround by using the abp.ajax function to take care of the login but still use our angular script for everything else.
Hello,
We have decided to take our login/page and make it more angular. However when we did this we noticed some weird responses from the server whenever we are trying to make API calls from the login page. For example, we submit the login details(using $http.post) and the server would response with an html page not a jsonresult as we expect from the action. When we login successfully, we will 302 response from the api call.
We are using MVC with angular
Here is the Login Action controller we are trying to call:
[HttpPost]
[UnitOfWork]
[DisableAuditing]
[DontWrapResult]
public virtual async Task<JsonResult> Login(LoginViewModel loginModel, string returnUrl = "", string returnUrlHash = "", string service= "", string serviceReturnUrl = "")
{
CheckModelState();
if (loginModel.LogIntoHost)
{
loginModel.TenancyName = null;
}
_unitOfWorkManager.Current.DisableFilter(AbpDataFilters.MayHaveTenant);
var loginResult = await GetLoginResultAsync(loginModel.UsernameOrEmailAddress, loginModel.Password, loginModel.TenancyName);
if (loginResult.User.ShouldChangePasswordOnNextLogin)
{
loginResult.User.SetNewPasswordResetCode();
return Json(new AjaxResponse
{
TargetUrl = Url.Action(
"ResetPassword",
new ResetPasswordViewModel
{
UserId = SimpleStringCipherProvider.Encrypt(loginResult.User.Id.ToString()),
ResetCode = loginResult.User.PasswordResetCode
})
});
}
await SignInAsync(loginResult.User, loginResult.Identity, loginModel.RememberMe);
var userRoles = await _userManager.GetRolesAsync(loginResult.User.Id);
try
{
var token = await _ssoManager.Login(loginResult.User, loginResult.Tenant.Id, string.Join(",", userRoles));
await _cacheManager.GetCache<string, string>(string.Format("{0}{1}UserSSO", loginResult.User.Id, loginResult.Tenant.Id)).SetAsync("token", token);
if (!service.IsNullOrEmpty() && returnUrl.Contains("http"))
{
var appendQuery = returnUrl.Contains("?") ? string.Format("&authToken={0}&returnUrl={1}", token, serviceReturnUrl) : string.Format("?authToken={0}&returnUrl={1}", token, serviceReturnUrl);
returnUrl = returnUrl + appendQuery;
returnUrl = Url.Action("SSO", "Application", new { returnUrl = returnUrl });
}
}
catch(Exception exp)
{
_logger.Error("Error Logging into SSO Server", exp);
}
if (string.IsNullOrWhiteSpace(returnUrl))
{
returnUrl = Url.Action("Index", "Application");
}
if (!string.IsNullOrWhiteSpace(returnUrlHash))
{
returnUrl = returnUrl + returnUrlHash;
}
return Json(new AjaxResponse { TargetUrl = returnUrl });
}
Here is the login js call
var CurrentPage = function () {
var handleLogin = function () {
var $loginForm = $('.login-form');
$loginForm.validate({
errorElement: 'span', //default input error message container
errorClass: 'help-block', // default input error message class
focusInvalid: false, // do not focus the last invalid input
rules: {
username: {
required: true
},
password: {
required: true
}
},
invalidHandler: function (event, validator) {
$loginForm.find('.alert-danger').show();
},
highlight: function (element) {
$(element).closest('.form-group').addClass('has-error');
},
success: function (label) {
label.closest('.form-group').removeClass('has-error');
label.remove();
},
errorPlacement: function (error, element) {
error.insertAfter(element.closest('.input-icon'));
},
submitHandler: function (form) {
$loginForm.find('.alert-danger').hide();
}
});
$loginForm.find('input').keypress(function (e) {
if (e.which == 13) {
if ($('.login-form').valid()) {
$('.login-form').submit();
}
return false;
}
});
$loginForm.submit(function (e) {
e.preventDefault();
if (!$('.login-form').valid()) {
return;
}
abp.ui.setBusy(
$('.login-form'),
abp.ajax({
contentType: app.consts.contentTypes.formUrlencoded,
url: $loginForm.attr('action'),
data: $loginForm.serialize()
}).done(function (response) {
console.log('response: ', typeof response);
})
);
});
$('a.social-login-icon').click(function() {
var $a = $(this);
var $form = $a.closest('form');
$form.find('input[name=provider]').val($a.attr('data-provider'));
$form.submit();
});
$loginForm.find('input[name=returnUrlHash]').val(location.hash);
$('input[type=text]').first().focus();
}
return {
init: function () {
handleLogin();
}
};
}();
We have tenant users that will need to login and have another filter that filters all of the "companies" they are allowed to access.
I have seen examples of the data filter boilerplate uses work for a specific value but not for a range and I want to know if it is possible.
Thanks @hikalkan and everyone else help on this.
I have decided the second option that you mentioned is good and I have made some great progress but I have ran into another issue. Locally when I have the two application running and I try to login to the second app. After the first app redirects back to the second app. The AbpSession information from the first app is referenced in the Second app which causes an error. How is that possible? When I go directly to the second app the page loads the data correctly. Is the Clams Identity unique per application or is that information shared?
We already use the Tenant information but a tenant could have multiple companies that a user could reference for different pages. So I would like to be able to set that information up in the Session then use dynamic filters to reference the CompanyId. But I am not sure how to add the property to the session.
Thanks!
I need to extend the AbpSession to keep up with a value that I can use through out the system. We have an another level the user can fall into. (lets say a Company) so when the user logs in under a company I want to save that information in the AbpSessions so I can apply filters to based on that value.
Is there a way I can add that field to the ABPSession object?
<cite>ismcagdas: </cite> Hi,
You can use token based authentication for your other apps. See <a class="postlink" href="https://aspnetzero.com/Documents/Development-Guide#token-based-authentication">https://aspnetzero.com/Documents/Develo ... entication</a>
I could but I still would need to have the user's account automatically set up in the other application if it does not exists. I read some articles on stackoverflow about how they handle this issues so I am going to try to follow up on that.
Thanks for your help.
<cite>ismcagdas: </cite> Hi,
Does any of your jobs are accessing a different database ? If so it might be a MSDTC problem. MSDTC service must be up and running. If your SQL Server is on a different server, then MSDTC service must be up and running on both machines.
If not, does this happen randomly or is it always in this way ?
It was at first but I removed all external database calls. It only references the default database.
For this job it has always been this way. I get a large list of orders then I process each one against another set on the server. I wonder if it is because I don't make any database calls while the process is running. Kinda of like how some apps log you out after a few min. of inactivity.
My App and Database are on two different servers and I think MSDTC is running. I will check on this though.
Thanks for you help. I was able to get around temporarily but disabling UOW and manually calling new UOWs when I needed access the database after the application timeout happens.
I may be missing something but I have a few long running processes that are failing to complete because the transaction is timing out.
I have tried to set the transaction timeout to an extremely large number but it always fails after ten minutes regardless.
Here is the error message I receive after letting the process run longer than ten minutes.
System.AggregateException
One or more errors occurred.
System.AggregateException: One or more errors occurred. ---> Hangfire.BackgroundJobClientException: Background job creation failed. See inner exception for details. ---> System.Transactions.TransactionException: The operation is not valid for the state of the transaction. ---> System.TimeoutException: Transaction Timeout
--- End of inner exception stack trace ---
at System.Transactions.TransactionState.EnlistPromotableSinglePhase(InternalTransaction tx, IPromotableSinglePhaseNotification promotableSinglePhaseNotification, Transaction atomicTransaction, Guid promoterType)
at System.Transactions.Transaction.EnlistPromotableSinglePhase(IPromotableSinglePhaseNotification promotableSinglePhaseNotification, Guid promoterType)
at System.Transactions.Transaction.EnlistPromotableSinglePhase(IPromotableSinglePhaseNotification promotableSinglePhaseNotification)
at System.Data.SqlClient.SqlInternalConnection.EnlistNonNull(Transaction tx)
at System.Data.SqlClient.SqlInternalConnection.Enlist(Transaction tx)
at System.Data.ProviderBase.DbConnectionInternal.ActivateConnection(Transaction transaction)
at System.Data.ProviderBase.DbConnectionPool.PrepareConnection(DbConnection owningObject, DbConnectionInternal obj, Transaction transaction)
at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection)
at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal& connection)
at System.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& connection)
at System.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
at System.Data.SqlClient.SqlConnection.TryOpenInner(TaskCompletionSource`1 retry)
at System.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry)
at System.Data.SqlClient.SqlConnection.Open()
at Hangfire.SqlServer.SqlServerStorage.CreateAndOpenConnection()
at Hangfire.SqlServer.SqlServerStorage.UseConnection[T](Func`2 func)
at Hangfire.SqlServer.SqlServerConnection.CreateExpiredJob(Job job, IDictionary`2 parameters, DateTime createdAt, TimeSpan expireIn)
at Hangfire.Client.CoreBackgroundJobFactory.Create(CreateContext context)
at Hangfire.Client.BackgroundJobFactory.<>c__DisplayClass7_0.<CreateWithFilters>b__0()
at Hangfire.Client.BackgroundJobFactory.InvokeClientFilter(IClientFilter filter, CreatingContext preContext, Func`1 continuation)
at Hangfire.Client.BackgroundJobFactory.Create(CreateContext context)
at Hangfire.BackgroundJobClient.Create(Job job, IState state)
--- End of inner exception stack trace ---
at Hangfire.BackgroundJobClient.Create(Job job, IState state)
at Abp.Hangfire.HangfireBackgroundJobManager.EnqueueAsync[TJob,TArgs](TArgs args, BackgroundJobPriority priority, Nullable`1 delay)
at NMI.SmartMarketBusiness.MarketServices.MarketServiceExportBackgroundJob.<>c__DisplayClass10_1.<<Execute>b__3>d.MoveNext()
--- End of inner exception stack trace ---
at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken)
at NMI.SmartMarketBusiness.MarketServices.MarketServiceExportBackgroundJob.Execute(MarketServiceExportBackgroundJobArgs args)
---> (Inner Exception #0) Hangfire.BackgroundJobClientException: Background job creation failed. See inner exception for details. ---> System.Transactions.TransactionException: The operation is not valid for the state of the transaction. ---> System.TimeoutException: Transaction Timeout
--- End of inner exception stack trace ---
at System.Transactions.TransactionState.EnlistPromotableSinglePhase(InternalTransaction tx, IPromotableSinglePhaseNotification promotableSinglePhaseNotification, Transaction atomicTransaction, Guid promoterType)
at System.Transactions.Transaction.EnlistPromotableSinglePhase(IPromotableSinglePhaseNotification promotableSinglePhaseNotification, Guid promoterType)
at System.Transactions.Transaction.EnlistPromotableSinglePhase(IPromotableSinglePhaseNotification promotableSinglePhaseNotification)
at System.Data.SqlClient.SqlInternalConnection.EnlistNonNull(Transaction tx)
at System.Data.SqlClient.SqlInternalConnection.Enlist(Transaction tx)
at System.Data.ProviderBase.DbConnectionInternal.ActivateConnection(Transaction transaction)
at System.Data.ProviderBase.DbConnectionPool.PrepareConnection(DbConnection owningObject, DbConnectionInternal obj, Transaction transaction)
at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection)
at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal& connection)
at System.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& connection)
at System.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
at System.Data.SqlClient.SqlConnection.TryOpenInner(TaskCompletionSource`1 retry)
at System.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry)
at System.Data.SqlClient.SqlConnection.Open()
at Hangfire.SqlServer.SqlServerStorage.CreateAndOpenConnection()
at Hangfire.SqlServer.SqlServerStorage.UseConnection[T](Func`2 func)
at Hangfire.SqlServer.SqlServerConnection.CreateExpiredJob(Job job, IDictionary`2 parameters, DateTime createdAt, TimeSpan expireIn)
at Hangfire.Client.CoreBackgroundJobFactory.Create(CreateContext context)
at Hangfire.Client.BackgroundJobFactory.<>c__DisplayClass7_0.<CreateWithFilters>b__0()
at Hangfire.Client.BackgroundJobFactory.InvokeClientFilter(IClientFilter filter, CreatingContext preContext, Func`1 continuation)
at Hangfire.Client.BackgroundJobFactory.Create(CreateContext context)
at Hangfire.BackgroundJobClient.Create(Job job, IState state)
--- End of inner exception stack trace ---
at Hangfire.BackgroundJobClient.Create(Job job, IState state)
at Abp.Hangfire.HangfireBackgroundJobManager.EnqueueAsync[TJob,TArgs](TArgs args, BackgroundJobPriority priority, Nullable`1 delay)
Hello all,
We are developing multiple applications that are use the boilerplate but I would like for the user to be able to have one login and be able to login or use a service from a different applications.
Kind of like google login process for it's services.
Any help would be great!
Thanks,