Using AspNetBoilerplate. I'm being asked to create a way to provide a user to unsubscribe from a service prior password check which is where I'm stuck.
[AbpAuthorize]
public class UserCompaniesManagerAppService : InvoiceAppServiceBase, IApplicationService
{
public async Task CancelSubscription(CheckPasswordDto input)
{
using (CurrentUnitOfWork.SetTenantId(AbpSession.TenantId))
{
var user = await GetCurrentUserAsync();
//verify pass
if (await UserManager.CheckPasswordAsync(user, input.Password))
{
await UserManager.ResetAccessFailedCountAsync(user);
//TODO: unsubscribe
}
else
{
//response from server when wrong password
await UserManager.AccessFailedAsync(user);
var count = await UserManager.GetAccessFailedCountAsync(user);
var maxAttempts = await SettingManager.GetSettingValueAsync<int>(
AbpZeroSettingNames.UserManagement.UserLockOut.MaxFailedAccessAttemptsBeforeLockout);
throw new UserFriendlyException("tried " + count.ToString() + " left attempts " + (maxAttempts - count).ToString());
}
}
}
I'm using "UserFriendlyException" which is what is suggested from docs. I was expecting to see the times wrong password was done and the times left for a correct password. Server response this way.
{
"result": null,
"targetUrl": null,
"success": false,
"error": {
"code": 0,
"message": "tried 1 left attempts 2",
"details": null,
"validationErrors": null
},
"unAuthorizedRequest": false,
"__abp": true
}
Thing is, that if I keep executing it, it stays on those values. Also, the DB doesn't count the failed attempts. No data is written on AbpUsers table.
I've tried using, just in case, Task<string>
and return the message that way and it works fine, the counters, the fields in AbpUsers and the lockdown. But I know this shouldn't be done this way but to provide an object as a response like throw.
ABP's Conventional Unit of Work is scoped around your App Service method CancelSubscription
:
if no exception is thrown, it commits the transaction at the end of it. If an exception is thrown, it rolls everything back.
Begin a new unit of work uow
that gets completed:
using (var uow = _unitOfWorkManager.Begin(TransactionScopeOption.RequiresNew))
{
await UserManager.AccessFailedAsync(user);
uow.Complete();
}
var count = await UserManager.GetAccessFailedCountAsync(user);
var maxAttempts = await SettingManager.GetSettingValueAsync<int>(
AbpZeroSettingNames.UserManagement.UserLockOut.MaxFailedAccessAttemptsBeforeLockout);
//response from server when wrong password
throw new UserFriendlyException("tried " + count.ToString() + " left attempts " + (maxAttempts - count).ToString());
Alternatively, you can make AccessFailedAsync
virtual
and mark it with the UnitOfWork
attribute:
[UnitOfWork(TransactionScopeOption.RequiresNew)]
public virtual async Task AccessFailedAsync(User user)
{
// ...
}