I try to implement my custom Session to store some information (es. companyId) I use this code
public interface IMySession : ITransientDependency
{
long CompanyId { get; set; }
void SetCompanyId(long companyId);
}
public class NullableMySession : IMySession
{
private static readonly NullablemySession SingletonInstance = new NullableMySession();
public static NullableMySession Instance
{
get { return NullableMySession.SingletonInstance; }
}
public long CompanyId { get; set; }
public void SetCompanyId(long companyId)
{
}
}
public class MySession : IMySession
{
public long CompanyId
{
get;
set;
//get
//{
// var claimsPrincipal = Thread.CurrentPrincipal as ClaimsPrincipal;
// if (claimsPrincipal == null)
// {
// return 0;
// }
// var company = claimsPrincipal.Claims.FirstOrDefault(c => c.Type == myConsts.SessionCompany);
// if (company == null || string.IsNullOrEmpty(company.Value))
// {
// return 0;
// }
// return System.Convert.ToInt32(company.Value);
//}
}
public void SetCompanyId(long companyId)
{
var claimsPrincipal = Thread.CurrentPrincipal as ClaimsPrincipal;
var claimsIdentity= Thread.CurrentPrincipal.Identity as ClaimsIdentity;
var company = claimsPrincipal.Claims.FirstOrDefault(c=> c.Type == myConsts.SessionCompany);
if (company != null)
{
claimsIdentity.RemoveClaim(company);
}
claimsIdentity.AddClaim(new Claim(myConsts.SessionCompany, companyId.ToString()));
}
}
If I try to set value after login on Principal the new value is not persisted on Principal, so I move to simple solution store on session. I add a
public IMySession MySession { get; set; }
protected demoAppServiceBase()
{
LocalizationSourceName = clayConsts.LocalizationSourceName;
MySession = NullableMySession.Instance;
}
But Any time to redo a call from API the value is not persisted on mySession so I add the row on coreModule preInitialize
IocManager.IocContainer.Register(Component.For<IMySession, MySession>().ImplementedBy<MySession>());
After do that the value is persistend on all call, but is it the correct way or I make some mistakes?
Mattia
12 Answer(s)
-
0
You should get
CompanyId
from claims, instead of storing it in a property on a singleton. Why did you comment that out? -
0
I try that way but when I need to change that value is impossible... the value is store on claims during the call but on second call the value is disapeared
-
0
You should not change claims dynamically. Do it when
ClaimsPrincipal
is created:https://gist.github.com/ismcagdas/6f2a9a3b5d7b907cb8d94a72124d59a1
-
0
@aaron this work on ABPZERO core, my solution is on .NET 4.6.1. Any suggestion?
-
0
Do you mean MVC 5?
-
0
Yes
-
0
https://gist.github.com/hikalkan/67469e05475c2d18cb88
-
0
@aaron my test work fine and mY custom session do what I need.
So know I found an issue, during debugging. If I restart the debug session my custom will be lost until I redo a F5 on my browser. When I do that ABP call SessionAppService and in GetCurrentLoginInformations I reset the data for my custom session.
The same happen on login in account controller. But if I don't do a F5 AbpSession is populate (I read the abpSession is on cookie) but my session no wich is the entrt point where abpsession is restored from cookies?
-
0
AbpSession
doesn't use cookies. ABP is open source, so you can see the source code ofClaimsAbpSession
. -
0
@aaron thank for the calrification but if I call from my web site after debug restart I found data in my AbpSession, so some method call AbpSession to reload it (like when you do the login or do a reload page) I need to identify this event and add my logic to restore my data from DB
-
0
ClaimsAbpSession
gets values from the claims on the fly. Please see the source code that has been linked for your convenience.The sample code for adding a new property to session has also been provided in the Gist linked a little further up.
-
0
Hi @aaron
I complete the integration with my custom session (ABP MVC + ZERO ver 6.6.1). During test I use a single tenant but after move to production we see a strnge situation in some case our session change the value from user to use, this happen because we use the AppSessionAppService to inject our session and any use call this method (login or F5) the session change with the lastest one.
I search the correct place to put my custom session and I found it in UserManager
public override async Task<ClaimsIdentity> CreateIdentityAsync(User user, string authenticationType) { var identity = await base.CreateIdentityAsync(user, authenticationType); using (var uo = _unitOfWorkManager.Begin()) { _unitOfWorkManager.Current.SetTenantId(user.TenantId); // Read Company for user from db var companyId = await _settingManager.GetSettingValueForUserAsync<long>("userSettings.CompanyId", user.TenantId, user.Id); identity.AddClaim(new Claim(CustomClaim.ClaimCompany, companyId.ToString())); uo.Complete(); } return identity; }
In this way my user has correct value on every roundtrip.
The only problem is when I need to change the value of my session data and is not allowed so I need to force a signIn & signOut
User user; ClaimsIdentity identity; using (var uo = _unitOfWorkManager.Begin()) { user = await ClayUserManager.FindByIdAsync(AbpSession.UserId.Value); identity = await ClayUserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie); uo.Complete(); }
I need to use UOW beacuse in code above set the new value on DB. So in that way I can use my custom sassion
public interface IMySession : ITransientDependency { long? CompanyId { get; } }
And the implementation is
//// Take care of name to use auto registration path MySession -> IMySession public class MySession : ClaimsAbpSession, IMySession { public MySession( IPrincipalAccessor principalAccessor, IMultiTenancyConfig multiTenancy, ITenantResolver tenantResolver, IAmbientScopeProvider<SessionOverride> sessionOverrideScopeProvider) : base(principalAccessor, multiTenancy, tenantResolver, sessionOverrideScopeProvider) { } public long? CompanyId { get { var company = PrincipalAccessor.Principal?.Claims.FirstOrDefault(c => c.Type == appConsts.ClaimCompany); if (string.IsNullOrEmpty(company?.Value)) { return null; } return System.Convert.ToInt64(company.Value); } //... } }
Now all data is stored on claim and user filter company works fine based on session value.
I hope this explanation can be useful for other user.