Implementing user session in Sencha and SpringBoot - authentication

I am trying to make a web app in Sencha Touch with Springboot as my back-end. My app is going to have users and each one of them is going to have their own separate activity. How do I make my app "know" what user is logged in so it can display their specific details? I am a newbie and don't know exactly how this needs to be done, especially on the server side (Springboot). If somebody could throw some light, that would be awesome! Thanks!

Assuming you are planning to use Spring Security, the current-user data can be obtained through its principal. There are a few ways to get the principal. One way is to have a principal parameter in the controller method, and Spring will inject it. Like this:
#RequestMapping(value = "/user", method = RequestMethod.GET)
#ResponseBody
public String currentUserName(Principal principal) {
return principal;
}
Another way would be to have a utility method like this:
public static User getUser() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null) {
Object principal = auth.getPrincipal();
if (principal instanceof User) {
return (U) principal;
}
}
return null;
}
This can then be called from the controller method.

Related

Perpetual expiry of claims in SignInWithClaimsAsync

I am using ASP.NET Core 3.1 with Identity and storing some basic user information like their full name in a claim using the code below (I am aware of checking password and stuff, ignoring it for brevity):
var user = await _userManager.FindByNameAsync(Input.Username);
var claims = new List<Claim>
{
new Claim("UserFullname", user.Fullname, ClaimValueTypes.String)
}
await _signInManager.SignInWithClaimsAsync(user, Input.RememberMe, claims);
I am accessing it in the _Layout.cshtml using the line below:
var userFullname = User.Claims.Single(c => c.Type == "UserFullname").Value;
The problem is, this seems to expire in some time even though the user is still logged in. I want this to be perpetual until the user logs out.
I am sure there has to be some way in startup.cs to control this and as far as possible, I would like to avoid overriding anything.
--EDIT--
As mentioned in the comments for answer by #yinqiu, I tried the cookie authentication scheme using the line below:
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme);
But it did not help either.
I think you can try to override the SignInWithClaimsAsync method.
public override async Task SignInWithClaimsAsync(ApplicationUser user, AuthenticationProperties authenticationProperties, System.Collections.Generic.IEnumerable<System.Security.Claims.Claim> additionalClaims)
{
if (authenticationProperties != null && authenticationProperties.IsPersistent)
{
authenticationProperties.ExpiresUtc = DateTimeOffset.UtcNow.AddYears(1);
}
await base.SignInWithClaimsAsync(user, authenticationProperties, additionalClaims);
}
This is the appropriate solution of your case:
If you are inheriting Identity Classes (IdentityRole,IdentityUser) into your custom classes then you need to use your inherited classes otherwise you use the default Identity Classes. You need a custom ClaimIdentity Class let assume 'ApplicationClaimsIdentityFactory' and this class should be inherited by UserClaimsPrincipalFactory<AspNetUser, AspNetRole>
Step1 Register your dependencies in Startup.cs
services.AddIdentity<AspNetUser, AspNetRole>().AddEntityFrameworkStores<ICRCOMDMSEntities>().AddDefaultTokenProviders();
services.AddScoped<IUserClaimsPrincipalFactory<AspNetUser>, ApplicationClaimsIdentityFactory>();
Step2:
Override the method CreateAsync in your custom claimsIdentityFactory Calss and here you need to create your custom claims and return like
public async override Task<ClaimsPrincipal> CreateAsync(AspNetUser user)
{
var principal = await base.CreateAsync(user);
((ClaimsIdentity)principal.Identity).AddClaims(new[] {
new Claim("UserLastLogin", user.LastLoginDate.ToString("dd/MM/yyyy hh:mm:ss tt"))
});
return principal;
}
Now your claims persists until user is logged in.

ServiceStack: Can we Pass Data through a RequestFilterAttribute to the calling service

Maybe I'm thinking about this wrong, but I'm trying to create a custom attribute for our CMS to handle auth checks.
https://gist.github.com/sitefinitysteve/62ab761256a64a84d8a6#file-sitefinityjwt-cs-L39
So if this service is called from within the CMS from a logged in user, user data is all there for the service method already.
But in the context of being called from an app, the user is technically Anonymous, however I can decode the token and get the user just fine... but not sure how to like pass that over to the service.
Am I just maybe looking at this wrong, and the proper thing to do is to call a CMS API method to just log that person in (seems slow if I already have the persons user object from line 33, and the service context expires instantly.
Use Request.Items Dictionary
You would use the IRequest.Items dictionary for any data you want to pass throughout ServiceStack's Request Pipeline:
//RequestFilter:
req.Items["info"] = new MyRequestInfo { ... };
In Service:
var info = (MyRequestInfo)base.Request.Items["info"];
Have DTO's share common interface
Another option for adding extra info to your Service is to have Request DTO's implement an interfaces, e.g:
public interface IHasInfo
{
MyRequestInfo Info { get; set; }
}
Which you could then populate in your Request Filter, e.g:
((MyRequestInfo)dto).Info = new MyRequestInfo { ... };
Access in Service like any other DTO property, e.g:
public object Any(Request request)
{
var info = request.Info;
}

Add extra parameter to every WCF call

We have WCF services (web hosted in IIS) separatd by domains. We added some claim based security by adding ClaimsAuthorizationManager and overriding the CheckAccess method. Basicaly, we check if the ClaimsPrincipal have the permission needed to execute the method.
Inside the service method :
public DemandePaeDto ObtenirInfoDemandePAE(int idPreDemande, int numeroSequencePreDemande)
{
if (!ClaimsPrincipal.Current.CheckAccess(Management, "DoSomething"))
return null;
Inside the ClaimsAuthorizationManager :
public class FacadeClaimsAuthorizationManager : ClaimsAuthorizationManager
{
public override bool CheckAccess(AuthorizationContext context)
{
var user = context.Principal;
var resource = context.Resource.First().Value;
foreach (var action in context.Action)
{
switch (resource)
{
case "Management":
case "Sales":
case "Product":
if (user.HasClaim(OurOwnCustomClaimTypes.Permission, action.Value))
{
return true;
}
break;
//Pour les cas non gérés
default:
return false;
}
}
return false;
}
}
The problem is when we need to test the services functionalities with WCF Storm of other test tool, we don't have the claims because we set the security mode to false. So we would like to add a custom parameter to all calls. That way we'd be able to bypass by returning true in the CheckAccess method. I've think about MessageInpectors, but still am wondering if it's the right approach. I wouldn't like to add the param to the contracts, because I'd have to modify every call in the application.
Do you have a suggestion ?
You will need to use a different ClaimsAuthorizationManager for your tests. Just derive a different version and use that in your testing environment. It could return true on all call for example.

UserNamePasswordValidator and Session Management

I'm using WCF custom Validator with HTTPS (.NET 4.5). Validate on success returns Customer object which I would like to use later. Currently I'm able to do it with Static variables which I like to avoid if possible. I tried to use HttpContext which becomes null in main thread. My understanding Validate runs under different thread. Is there any way I could share session info without involving DB or File share. See related threads here and here.
In Authentication.cs
public class CustomValidator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
//If User Valid then set Customer object
}
}
In Service.cs
public class Service
{
public string SaveData(string XML)
{
//Need Customer object here. Without it cannot save XML.
//HttpContext null here.
}
}
I can suggest you an alternative approach. Assuming that the WCF service is running in ASP.Net compatibility mode and you are saving the customer object to session storage. Create a class such as AppContext
The code would look something like this
public class AppContext {
public Customer CurrentCustomer {
get {
Customer cachedCustomerDetails = HttpContext.Current.Session[CUSTOMERSESSIONKEY] as Customer;
if (cachedCustomerDetails != null)
{
return cachedCustomerDetails;
}
else
{
lock (lockObject)
{
if (HttpContext.Current.Session[CUSTOMERSESSIONKEY] != null) //Thread double entry safeguard
{
return HttpContext.Current.Session[CUSTOMERSESSIONKEY] as Customer;
}
Customer CustomerDetails = ;//Load customer details based on Logged in user using HttpContext.Current.User.Identity.Name
if (CustomerDetails != null)
{
HttpContext.Current.Session[CUSTOMERSESSIONKEY] = CustomerDetails;
}
return CustomerDetails;
}
}
}
}
The basic idea here is to do lazy loading of data, when both WCF and ASP.Net pipelines have executed and HTTPContext is available.
Hope it helps.
Alright this should have been easier. Since the way UserNamePasswordValidator works, I needed to use custom Authorization to pass UserName/Password to the main thread and get customer info again from the database. This is an additional DB call but acceptable workaround for now. Please download code from Rory Primrose's genius blog entry.

How to store info about the authenticated user in WCF?

I have a WCF service where I use a customUserNamePasswordValidatorType (specified in the behaviors\serviceBehaviors\serviceCredentials\userNameAuthentication section of the web.config file).
My custom UserNamePasswordValidator works that way:
public bool Authenticate(string userName, string password)
{
If ( IsUserValid(username, password) )
{
UserInfo currentUser = CreateUserInfo(username);
//
// Here I'd like to store the currentUser object somewhere so that
// it can be used during the service method execution
//
return true;
}
return false;
}
During the service call execution, I need to access the info of the authenticated user. For instance I would like to be able to implement:
public class MyService : IService
{
public string Service1()
{
//
// Here I'd like to retrieve the currentUser object and use it
//
return "Hello" + currentUser.Name;
}
}
My question is how and where should I store the information during the authentication process so that it can be accessed during the call execution process? That storage should only last as long as the "session" is valid.
By the way, I don't use (and don't want to use) secure sessions and/or reliable sessions. So I have both establishSecuritytContext and reliableSessions turned off.
I'm thinking of enabling ASP.NET Compatibility Mode to store the user info in the HttpContext.Current.Session but I have the feeling it's not how it should be done.
Store anything that needs to be persisted into a persistant store - e.g. a database, that's the best way to go.
Store the user info in a user table, e.g. the ASP.NET membership system or something of your own. Keep some kind of a identifying token (username, ID etc.) at hand to retrieve that info from the database when needed.
You should strive to have a stateless WCF service whenever possible - it should never depend on a "state" of any kind other than what's safely stored in a database.