I have a booking application where a customer will create a reservation. I do not want them to have to create an account and log in, so they will modify/view their reservation using a Confirmation code (like the airlines use) and the last 4 of their credit card (again, like airlines). My reservation class already has a primary key, a GUID, however, I do not want to give that to the customer, I want something nicer to look at like a 6-8 digit alpha code.
I am using Entity Framework and C#/ASP.NET Core, and while I COULD generate the value in my code, check with the DB (MSSQL) that the value has not been used, and then persist if it is unique, I would rather have a single operation if I could. Is the accepted way of doing something like this to have the database generate the value or is there a more EF way of doing it?
CodePudding user response:
Like a two-factor (TOTP) code, but based on your GUID instead of a timestamp?
// userData should be populated with whatever immutable user data you want
// applicationSecret should be a constant
public string ComputeCode(byte[] userData, byte[] applicationSecret, int length)
{
using var hashAlgorithm = new HMACSHA256(applicationSecret);
var hash = hashAlgorithm.ComputeHash(userData);
return BitConverter.ToString(hash).Replace("-", "").Substring(0, length);
}
CodePudding user response:
I can't speak to the EF-related aspects of your question, but I recently had to figure out a way to generate unique, user-friendly IDs for a personal project.
What I eventually settled on was the following:
- Start with a 32-bit integer. (In my case it was an incrementing database ID.)
- "Encrypt" the integer using RC5 with a block size of 32 bits. This scrambles the key space. You'll probably have to write your own RC5 implementation, but it's a simple algorithm. (Mine was <100 lines of python.)
- Encode the resulting 4 bytes in Base32. I recommend z-base-32 for the most user-friendly alphabet. You might have to write your own Base32 implementation, but again, it's quite simple.
This algorithm produces a reversible mapping similar to the following:
1 <-> "4zm5cna"
2 <-> "5ytgepe"
3 <-> "e94rs4e"
etc.