Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Question
Tuesday, November 26, 2019 7:35 AM
I am having problems with **ITicketStore**. My original problem was this. Because I am using Asp.Net.Identity role/claims, however, when the user is stored the cookie information is too big and gives me an error `HTTP Error 400. The size of the request headers is too long.`. When you try to log in again and once logged in you get the same problem.
Previously (before Identity) I used to roll-my-own security. It looked a lot like Identity with Annotations etc. But the only thing passed around was a cookie which only contained your encrypted user Id. I had action filters that would manage this cookie and retrieve your permissions (roles/claims) and decide what you could and couldn't access. It also supported single logon and remote log out.
Looking around it was suggested I use ITicketStore (looks like others had the same problem). Knowing nothing about `ITicketStore` I did some investigation, but I couldn't find any tutorials about this and all the implementations I could find (here and elsewhere) would not run as in gave me 'red wavy' lines that would not resolve or run-time errors.
Eventually, I managed to cobble together a working version (i.e. no red wavies and no run-time errors), but now the whole thing doesn't work properly. When you close the browser the session is lost, e.g. you have to log in again and the user picks up no roles when you use `.IsInRole` or when you try
public async Task<List<string>> GetUserRoles(int id)
{
var user = await _userManager.FindByIdAsync(id.ToString());
var roles = await _userManager.GetRolesAsync(user);
return roles.ToList();
}
I'm obviously doing something wrong but I have no idea what. I'll continue to investigate, but I have a vain hope that the community here can help me out. Like I say all the implementations I found here and elsewhere don't work for one reason or another and I can't find any basic information to help me understand (er) the basics.
I'm using VS2019 and Asp.Net.Core 2.2
In my Startup.cs, I have this
services.ConfigureApplicationCookie(options =>
{
options.ExpireTimeSpan = TimeSpan.FromDays(14);
options.SlidingExpiration = true;
options.SessionStore = services.BuildServiceProvider().GetService<ITicketStore>();
});
I have an ITicketStore.cs class
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.Extensions.Caching.Memory;
using System;
using System.Threading.Tasks;
namespace OnsidacaWeb.Models
{
public class TicketStore : ITicketStore
{
private IMemoryCache _cache;
private const string KeyPrefix = "AuthSessionStore-";
public TicketStore(IMemoryCache cache)
{
_cache = cache;
}
public Task RemoveAsync(string key)
{
_cache.Remove(key);
return Task.FromResult(0);
}
public Task RenewAsync(string key, AuthenticationTicket ticket)
{
var options = new MemoryCacheEntryOptions
{
Priority = CacheItemPriority.NeverRemove
};
var expiresUtc = ticket.Properties.ExpiresUtc;
if (expiresUtc.HasValue)
{
options.SetAbsoluteExpiration(expiresUtc.Value);
}
options.SetSlidingExpiration(TimeSpan.FromMinutes(60));
_cache.Set(key, ticket, options);
return Task.FromResult(0);
}
public Task<AuthenticationTicket> RetrieveAsync(string key)
{
AuthenticationTicket ticket;
_cache.TryGetValue(key, out ticket);
return Task.FromResult(ticket);
}
public async Task<string> StoreAsync(AuthenticationTicket ticket)
{
var key = KeyPrefix + Guid.NewGuid();
await RenewAsync(key, ticket);
return key;
}
}
}
All replies (5)
Tuesday, December 3, 2019 8:57 AM âś…Answered
I could not get ITicketStore to work no matter what I tried. I even spent several days reading all the documents I could find on ITicketStore, it's not very well documented at all. And this seems like quite a common problem (the cookie thing and ITicketStore documentation).
The AuthenticationTicket was saving as I could see it in the database. The problem was that this would not bring back the user nor their attributes next time they logged on. In fact each time you close the browser (any browser) you would always have to log on again. The "IsSignedIn" feature would not work.
Anyway, I changed my application so that Asp.Net.Identity only picks up the user role. This solves the cookie size problem.
I've implemented my own functions to check the role-claims. Which works better I feel as any changes happen live so no need to log on/off to get new claims or revoke existing claims.
I have a service function, that takes an
IdentityUser<AppUser>
and a Claim name (string).
_adminService.UserHasClaim(user, ClaimName) // returns true or false if you have that claim or not
I have my own table, identical to the AspNetRoleClaims table that contains the values. The Asp.Net.Identity version of that table is now empty so the cookie doesn't contain any claims.
public bool UserHasClaim(AppUser user, string claimValue)
{
var claim = (from c in _context.AppUserRoleClaims
join t in _context.AppUserClaimTypes on c.ClaimID equals t.ID
join r in _context.UserRoles on c.RoleId equals r.RoleId
where r.UserId == user.Id && t.ClaimValue == claimValue select c).FirstOrDefault();
return (claim != null);
}
It might not be perfect or ideal but it works and I can't afford any more time trying to solve this using identity. I don't claim it to be ideal and I'll probably come back to it later in time.
Happy to take comments on a better workable solution, but for now that's how I've solved the problem.
DJack10
Wednesday, November 27, 2019 8:03 AM
Hi j4ck50nD,
Welcome to MSDN forum.
With ITicketStore , only a session identifier is sent to the client. The authenticate user info is stored on server side . When session lost(close the browser) the tickets are also lost since you are saving them to memory .
You can save the authentication tickets to database :
https://ml-software.ch/posts/implementing-a-custom-iticketstore-for-asp-net-core-identity
Hope this could help you.
Best Regards,
Tianyu
MSDN Community Support
Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact [email protected].
Friday, November 29, 2019 8:13 AM
Thanks for that. My implementation was based on that article but it didn't work. I used that implementation to save to the database and it was indeed saving to the database. What it wasn't doing was getting the data back next time you logged in. Unfortunately I don't know enough about ITicketStore and there is very little documentation that describes it so I wasn't able to debug the problem.
I've changed my solution to only partially use Asp.Net.Identity and the rest is my own omplementation
DJack10
Monday, December 2, 2019 1:39 AM
Hi DJack10,
Thanks for your feedback.
Could you please explain more about "only partially use Asp.Net.Identity and the rest is my own omplementation" For debugging, you can implement the application cookie events and set checkpoint on `RetrieveAsync` event to confirm whether ticket is correct retired when cookie pass from client side to server side during the request .
Hope all above could help you and any feedback will be excepted.
Best Regards,
Tianyu
MSDN Community Support
Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact [email protected].
Wednesday, December 4, 2019 7:51 AM
Hi DJack10,
Thank you for the feedback.
We are glad to hear that you have found the solution and we appreciate that you could share your solution with us.
If possible, you could mark your reply as answer and other forum members who are interested in this thread or have similar issue could refer to this thread.
Have a nice day : )
Best Regards,
Tianyu
MSDN Community Support
Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact [email protected].