remember anonymous users when navigating - c#

I'm trying to make a game with SignalR that can be played between two players.
I have an issue in remembering the anonymus players. At one point, the users are redirected to another page and there I'm lost.
Inspired by Mapping connections , I've been able to solve the authenticated users ( Context.User.Identity.Name ), but what should I do in order to remember the unaunthenticated users when they navigate through website? (from what I know the signalR ConnectionId changes every request).

Generate a cookie for them containing a random GUID and then use that in your connection mapping. Set the value as part of the initial HTML you send the browser. Read the value in your Hub via Context.RequestCookies.

Related

How to Logout user from a particular session Identity Server 4, .Net Core?

Using Identity Serve 4 with .Net Core 3.1, razor pages. Also using Cookie Authentication
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
Problem -
In a web application John logged-in 2 times
1st Login on Chrome
2nd Login on edge
So, if John again trying to logged-in on 3rd time on Firefox without logout from previous browsers, then I want to logout John from 1st Login on Chrome forcefully.
I can keep the track of logins in a Session table including Session Id, User Id etc.
But I don’t know how logout user from a particular session using Session Id.
Please help.
Thanks
ASP.NET Core provides an ITicketStore interface which allows you to get control of storing user sessions. Once you provide a class implementing this interface and register it, it will call your class when sessions are being created or verified which you can then store in a database however you like, including attaching arbitrary metadata like browser ID etc.
Now that you have user sessions in your database, you can separately query them and revoke as needed in other logic, including during logins. Since you now provide the session data, simply deleting the record effectively logs the user out from that session. Note that if you use any caching layer to reduce the store requests, you'd need to remove any cached copies as well.
Note that this is separate from IdentityServer and happens with ASP.NET Core itself.
This is a good tutorial that helped me implementing this in my app.
A sample of how it looks to register in Startup, where PersistentTicketStore is my implementation:
// Persistent ticket/cookie store to provide durable user sessions
services.AddSingleton<IUserSessionRepository, UserSessionRepository>();
services.AddSingleton<ITicketStore, PersistentTicketStore>();
services.AddOptions<CookieAuthenticationOptions>(CookieAuthenticationDefaults.AuthenticationScheme)
.Configure<ITicketStore>((options, store) => options.SessionStore = store);
Use the End Session Endpoint
The end session endpoint can be used to end a session and trigger a log out
In the log in process you will need to capture the id_token received from authentication and what user it belongs and store it on some dbo.table. You can use this same table to also keep track if a user has logged in more than once.
To log out a user or end a session you will need to pass the ID you saved as a query string parameter called id_token_hint in a GET call as shown below into:
GET /connect/endsession?id_token_hint={id_token}
For reference see the documentation here https://identityserver4.readthedocs.io/en/latest/endpoints/endsession.html#end-session-endpoint
Since you're saying you can keep track of logins, perhaps you should keep track of each session and assign a number somewhere indicating when it was logged in (1 for Chrome, 2 for edge, 3 for Firefox).
Then each time a request is made, you check in your table what the lowest number is (1,2,3 etc), and if the session matches that number, you sign the user out from that session.
await
HttpContext.SignOutAsync(IdentityServerConstants.DefaultCookieAuthenticationScheme);
Since each browser will have their own cookie, you can use the above method.
After signing someone out, the next login can be assigned 4, and if 2 makes a request you log that client out.....
Also see this: https://github.com/IdentityServer/IdentityServer4/issues/736
I have implemented this.
When a user logs in, the session id (IUserSession.GetSessionIdAsync) is manually stored in our database. The previous value of this database field is used to create a logout_token which I send to my clients. You can have look at IdentityServer4.Infrastructure.BackChannelLogoutClient to figure out how to create the token and post.
All this assumes you have backchannel logout implemented ofcourse.

Redirect from successful stripe checkout

I am using Stripes payment gateway with C# .Net. I started with creating a checkout which redirects the user to Stripe's payment gateway (I didnt want the hassle of maintaining the card numbers etc so this way it forwards to Stripe to ask for the card details, process the payment etc) https://stripe.com/docs/payments/checkout/one-time - this was done in code-behind.
I set my success URL as www.example.com/myHandler.ashx (Generic Handler)- this URL sets the order id as successful. My handler code is similar to https://stripe.com/docs/webhooks/build (since im using a Generic Handler i'm using forms and not MVC)
After a successful payment, the payment is recorded to my database.
Considering this is a webhook, how do i display/redirect to a thank you page?
You have more than one way to solve this.
Option 1:
Combine the success page with your webhook. This means it will display the page to the user and update the state of the transaction on the backend.
your url would look like this
SuccessUrl = "https://example.com/success?session_id={CHECKOUT_SESSION_ID}"
Then use the session ID to handle the state change like you would with your webhook but return the html page to the user (Technically this wouldn't be a webhook).
Based on your question it could be that the SuccessUrl gives a session object as body because otherwise your current code shouldn't be working but I'm not sure.
To get the session object based on the Id you can make another call to stripe see:
https://stripe.com/docs/api/checkout/sessions/retrieve#retrieve_checkout_session
Once payment is successful, the Checkout Session will contain a reference to the Customer, and either the successful PaymentIntent or an active Subscription.
Option 2:
Create a webhook separately from your thank you page. This means that the SuccessUrl would be your thank you page.
The webhook needs to be defined separately and globally with stripe. You can look here on how this is done: https://stripe.com/docs/webhooks/configure

Using user's liked media in a list

On my website, I display a list of media from a specific tag. When the user is authenticated I would like to visually mark the media that he has voted on.
Currently, the list I'm displaying is read from my own database. I have a synchronizing process that subscribes to the tag. When I get these values from the /tags/tag-name/media/recent end point, I am not authenticated as any user.
The way I had planned to do this is that when a user logs in to my website, I hit the /users/self/media/liked end point and store them in session (running c# / MVC4). But I'm looking at the JSON result from that endpoint and it's a complete "Medias response" type with paging and everything. Basically at 20 per page, if a user has liked some 250 media, logging in would require 24 API calls and would take too long.
How do you handle this issue?
I could save the them to database...
I could save the complete list of liking users as I synchronize my media...
Thanks!
When the user is authenticated and then if you make the recent tag API call /tags/tag-name/media/recent with the user's access_token, then the JSON response will have a "user_has_liked" element, this will be true if the user has liked the picture and false if not.
You can use this data to display if user have liked or not from a list of tag media. You dont have to get all user liked media and compare, instagram tag media API already has this information if you use the user's access_token to make tag media call.

SignalR: How to stop creating new connection on page reload

Hi i am developing a chat application along with some other pages in my application. once i login i am maintaining the session of the user. My main intention is that user should get notification whenever another user connects to server.
The problem that i am facing is whenever i navigate to some other page in my application the connection is lost. How to stop this behaviour and continue the connection until user logs out.
I am using SignalR 2.0 in ASP.NET MVC4 project, any help??
Each connection only has a lifecycle for the duration of the time the user spends on a given page. When they navigate to another page, a new connection is established. Also, if a user has more than one tab or browser window open, they will have multiple connection Ids. I don't think you want to try to persist the connection Id beyond it's intended lifecycle.
In a similar scenario that I work on, we store the connectionIds OnConnect and delete them OnDisconnect. When a message needs to be sent to a given user, we send it to all of their connectionIds. This ensures that the message will be delivered to all tabs/windows.
EDIT 1 the following is in response to #Saurabh's comments:
Consider what the scope of the Hub is, and that of your other classes and the client. The Hub is there to facilitate communications between the browser and the server. While it's possible to do a lot of work within the hub, I think it's best to move most of the scope outside of communictions to other places.
The client knows that it just reloaded a page, so it's a good candidate for making the decision that this is a reconnect event.
_chatHub.server.reJoinRooms();
Then the Hub can query the user's rooms, by UserId, rather than ConnectionId.
public Task ReJoinRooms()
{
// get the user's rooms from your repository
// optionally get the user's connectionIds from your repository
// Clients.Caller.onJoinRooms(rooms);
// or Clients.Clients(_connectionIds).onJoinRooms(rooms);
}
Then the client can decide whether or not to take action:
$chatModule.client.onJoinRooms = function (rooms) {
for (var i in rooms) {
var _room = rooms[i];
// if I'm not already in this room, add it to my rooms
console.log('joining room', _room)
}
}
You could skin this many different ways. The client could own the scope of remembering rooms, instead of a server-side repository, too.
EDIT 2
If the number of groups/rooms that a user belongs to is ever-increasing, the above example may not scale up very well.
In that case, each user could join personal feed(s) instead (i.e. join a feed named for the user's GUID). We would keep track of each user that is affiliated with a group. When a message is sent to that group, we would iterate over those user's and publish a message to each feed.

Options for storing user information while logged in

What are some options in regards to maintaining user data while they are logged into my mvc4 site? I am building off of the Internet Application template and right now I am using User.Identity.Name to get the logged in user's username that they used to login with. I'd like to be able to also store and access several other pieces of information about the user across every page on the site. Can I still use User.Identity somehow and apply other attributes to it? I started building a ProfileModel that I could pass to views, but then I don't believe I would be able to pass other models to those views, not sure.
I'm open to suggestions as far as persistent user data, and thank you for any help.
EDIT 1: When I say persistent, I mean while they are logged in, the data itself is already stored in an external database, so I won't be doing any writing of this information, simply pulling it from the database, then holding onto it for the duration of them being logged in.
You'll want to leverage Session for that. Consider the following code:
Session["Profile"] = profileObj;
or maybe you just want to store a string:
Session["SomeSetting"] = value;
What you need to store in Session is unclear, and effectively irrelevant, you can store anything. You can access the Session from any Controller.
Then later on you can get the value out like this:
var profile = Session["Profile"];
// if the profile variable is null then it doesn't exist in Session yet
In response to #AaronLS, Session lasts the duration of the IIS session that's created when the user first accesses the site. Do keep in mind that these sessions are reset if inactive for a period of time (I believe the default IIS timeout is 20 minutes) so you'd want to leverage the null return value to know that you need to redirect the user to the login page to login again.

Categories