• Advertisement

How to check if the user is already logged in?

Recommended Posts

I need to implement a verification if the user is already logged in. At the moment my game doesn't verify this, so an account can log-in several times and I want to avoid this.

This is how I'm doing log-in authentication on game server:

void Session::authLogin(uint32_t id, std::string username, std::string token)
{
	// Return a valid alive connection, if doesn't exist, return nullptr
	auto dbcon = DatabaseManager::getFreeConnection();
	
	// Wait for a free connection
	if(!dbcon || dbcon->is_locked())
	{
		dbWait->expires_from_now(
		boost::posix_time::microseconds(
		DatabaseManager::DB_WAIT_TIME));
		
		dbWait->async_wait(boost::bind(
			&awaitAuthLogin, 
			boost::asio::placeholders::error, 
			weak_from_this(), 
			id, username, token));
		
		return;
	}
	
	// Lock connection
	DatabaseManager::Locker lock(dbcon);
	
	// Get Account Data
	auto pstmt = dbcon->prepare_statement(
			"SELECT `username`,`storage_gold`,`coins`,`ctl_code`,`vip_level`,"
			"unix_timestamp(`vip_expire_date`) FROM `account_data` WHERE `id`=? AND `username`=?");
	
	pstmt->push_uint(id);
	pstmt->push_string(username);
	
	uint32_t storage_gold = 0;
	uint32_t coins = 0;
	int32_t ctl_code = 0;
	uint32_t vip_level = 0;
	uint32_t vip_expire_date = 0;
		
	auto result = pstmt->execute_query();

	if(result->next())
	{	
		//Check token
		pstmt = dbcon->prepare_statement(
			"SELECT COUNT(*) FROM `token` WHERE `account_id`=? AND `token`=?");
		
		pstmt->push_uint(id);
		pstmt->push_string(token);
		
		auto token_result = pstmt->execute_query();
		
		if(!token_result->next())
		{
			// Invalid Token
			sendMessage(strdef::INVALID_TOKEN);
			closeSession();
			
			return;
		}
		
		storage_gold = result.get_int("storage_gold"),
		coins = result.get_int("coins"),
		ctl_code = result.get_int("ctl_code"),
		vip_level = result.get_int("vip_level");
		vip_expire_date = result.get_uint("unix_timestamp(`vip_expire_date`)");
	}
	else
	{
		// Invalid Login
		sendMessage(strdef::INVALID_USERNAME);
		closeSession();
		
		return;
	}

	// TODO: Check if account is logged in

	// *** I was thinking of doing an INSERT and 
	// if I get an ER_DUP_ENTRY error  it's because the account is logged in.
	
	try {
		// Insert account_stat
		pstmt = dbcon->prepare_statement(
			"INSERT INTO `account_stat` (`account_id`,`server_id`,`endpoint`,`mac`) VALUES(?,?,?,?)");
			
		pstmt->push_uint(id);
		pstmt->push_uint(getServerId());
		pstmt->push_string(getEndpoint());
		pstmt->push_string(getMacAddress());

		pstmt->execute();
	}
	catch(const mysql::exception& e) {
		// Already logged in
		if(e.error_code() == ER_DUP_ENTRY){
			sendMessage(strdef::ALREADY_LOGGED_IN);
			closeSession();
			
			return;
		}
	}
	
	// ***
	
	authLoginTimeout->cancel();
	
	// Make AccountInfo
	accountInfo = std::make_unique<AccountInfo>(id,
		username,
		token,
		storage_gold,
		coins,
		ctl_code,
		vip_level;
		vip_expire_date);
	
	// Load account storage
	loadStorage(id);
	
	// Send character list
	sendToCharacterLobby(id);
}

Can I have a problem doing this? Is there another way? I need it to be safe for multiple gameservers/dataservers.

If you have any tips to optimize it I accept :-)

Thanks in advance for helping me with this.

Edited by aikaproject

Share this post


Link to post
Share on other sites
Advertisement

The way this is generally done, is that each time you log in, a login cookie is generated. (Doesn't matter if it's for HTTP, HTTPS, TCP, or UDP protocols) The cookie is either just a long, strong cryptographic random string (256 bits or more, encoded as base64 or whatever) or it's a signed hash of some data, such as userid,logintime,sha256(userid+logintime+secret)

You have some kind of database (which could be something memory-only, such as Redis or even memcached) which maps userID to cookie. You can additionally also map cookie to session state; this is convenient for web pages, but less necessary for games with persistent session connections.

When you generate the cookie, you update the mapping from user to cookie value. If your cookie doesn't allow you to recover the user ID, you also update the mapping from cookie value to session information (which should include login time and user id)

Now, each time the user makes a web request, include this cookie value. You can then verify both that 1) the cookie value is one you issued, AND 2) that mapping from the user ID to cookie value, you get this cookie, and not some other cookie. (If the cookie for the user ID is not the provided one, then this is an earlier login that should now be invalid.)

Or, if the user uses TCP, this value should be stored in the server that keeps the TCP connection alive, and every 10 seconds or so, it should re-verify with the cookie database that the cookie value for the user is still the same. If the cookie value changes, it means the user logged in somewhere else, and thus this connection should be terminated.

If you have a robust, fast, message bus between all servers you could also broadcast an event saying "this user logged in" and have all connections listen to those events, and kick off connections with the same user id. There may be some race conditions in that approach, depending on how you implement it. so I wouldn't rely solely on that mechanism, but it might be convenient if you want faster-than-10-seconds kicks.

You can use a SQL database instead of a memory database; these cookies don't need to live longer than a session, but you can use some script in the database to clean up old values.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now


  • Advertisement
  • Advertisement
  • Popular Tags

  • Advertisement
  • Popular Now

  • Similar Content

    • By lonewolff
      Hi guys,
      I am having problems with trying to perform a basic 'shift left' on a char.
      char temp[1]; temp[0] = buffer[0] << 1; // buffer[0] is 0xff After this I have temp[0] writing to a file. Instead of being the expected 0x7F it is written as 0xF8.
      Any guidance on what I am doing wrong would be awesome.
      Thanks in advance
    • By sergio2k18
      Hi all
      this is my first post on this forum.
      First of all i want to say you that i've searched many posts on this forum about this specific argument, without success, so i write another one....
      Im a beginner.
      I want use GPU geometry clipmaps algorithm to visualize virtual inifinte terrains. 
      I already tried to use vertex texture fetch with a single sampler2D with success.
       
      Readed many papers about the argument and all speak about the fact that EVERY level of a geometry clipmap, has its own texture. What means this exactly? i have to 
      upload on graphic card a sampler2DArray?
      With a single sampler2D is conceptually simple. Creating a vbo and ibo on cpu (the vbo contains only the positions on X-Z plane, not the heights)
      and upload on GPU the texture containing the elevations. In vertex shader i sample, for every vertex, the relative height to te uv coordinate.
      But i can't imagine how can i reproduce various 2d footprint for every level of the clipmap. The only way i can imagine is follow:
      Upload the finer texture on GPU (entire heightmap). Create on CPU, and for each level of clipmap, the 2D footprints of entire clipmap.
      So in CPU i create all clipmap levels in terms of X-Z plane. In vertex shader sampling these values is simple using vertex texture fetch.
      So, how can i to sample a sampler2DArray in vertex shader, instead of upload a sampler2D of entire clipmap?
       
       
      Sorry for my VERY bad english, i hope i have been clear.
       
    • By mangine
      Hello. I am developing a civ 6 clone set in space and I have a few issues. I am using Lua for the logic and UI of the game and c++ directx 12 for the graphics. I need a way to send information between Lua and c++ occasionally and was wondering what is the best and most flexible (and hopefully fast) way to do this. Don't forget that I also need to send things from c++ back to Lua. I know of a lua extension called "LuaBridge" on github but it is a little old and I am worried that it will not work with directx 12. Has anybody done something similar and knows a good method of sending data back and forth? I am aware that Lua is used more and more in the industry and surely plenty of AAA game programmers know the answer to this. I want a good solution that will hopefully still be viable code in a couple of years...
    • By owenjr
      Hi there.
      I'm pretty new to this and I don't know if it has been asked before, but here I go.
      I'm developing a game using SFML and C++.
      I would like to use the "Tiled" tool to load maps into my game but I don't actually find any tutorial or guide on how to exaclty use it (I know that I have to read an XML file and stuff). I just step into diverse projects that make all a mess. 
      Anyone knows where can I find good information to make my map loader by myself?
      Thanks in advantage!!
    • By MHG OstryTM
      Hello guys,
      I've released my game for the first time. I'm very excited about it and I hope you'll enjoy the game - Beer Ranger. It's a retro-like puzzle-platfromer which makes you think a lot or die trying. You have a squad of skilled dwarfs with special powers and your goal is tasty beer. There is a lot of traps as well as many solutions how to endure them - it is up to your choice how to complete the level! 
      Link to the project: Project site
      Link to the Steam site with video: Beer Ranger
      Have fun and please write feedback if you feel up to.
      Some screens: 




  • Advertisement