Vincent van der Linden
Vincent van der Linden

Reputation: 219

Pass id, but don't show it in the actual url

I am trying to get friendly urls. The friendly url at the moment are there like this:

localhost/customer/1/namehere

I want them like this:

localhost/customer/namehere

But still get want id (because I search my database with this id). What are my possibilities? And is this even possible?

This is my MapRoute:

context.MapRoute(
            "Customer_Default",
            "customer/{customername}/",
            new { controller = "customer", action = "view", id = "", customername = "" }
        );

This is how I link:

@Html.ActionLink(c.Bedrijfsnaam, "view", "customer", new { id = c.Klantnummer, customername = UrlEncoder.ToFriendlyUrl(c.Bedrijfsnaam) }, null)

Thanks.

Update: Oh, it doesn't matter if the user changes it. I just want it to not show. So that the user can easily change the url to where they want to go. And don't have to worry about ids. (But I still need it. :))

Upvotes: 5

Views: 2127

Answers (3)

xanatos
xanatos

Reputation: 111870

You could for example encrypt the id + add some hash on it. In this way the user couldn't simply change it.

Or you could simply encrypt your id with a symmetric cipher, like AES or DES. The resulted id would be longer (because they work in blocks of 64-256 bits) and it wouldn't be possible to change a random character and obtain a valid id (technically with enough tries one could do it... Good luck!)

A code example

// Generate key. You do it once and save the key in the web.config or in the code
var encryptorForGenerateKey = Aes.Create();
encryptorForGenerateKey.BlockSize = 128;
encryptorForGenerateKey.KeySize = 128;
encryptorForGenerateKey.GenerateKey();
encryptorForGenerateKey.GenerateIV();

var key = encryptorForGenerateKey.Key;
var iv = encryptorForGenerateKey.IV;

// Encrypt

var encryptor = Aes.Create();
var encryptorTransformer = encryptorForGenerateKey.CreateEncryptor(key, iv);

int id = 123;
var bytes = BitConverter.GetBytes(id);
var encrypted = encryptorTransformer.TransformFinalBlock(bytes, 0, bytes.Length);
var encryptedString = BitConverter.ToString(encrypted);

Console.WriteLine(encryptedString);

// Decrypt

var decryptor = Aes.Create();
var decryptorTransformer = decryptor.CreateDecryptor(key, iv);

String[] arr = encryptedString.Split('-');
byte[] encrypted2 = new byte[arr.Length];
for (int i = 0; i < arr.Length; i++)
{
    encrypted2[i] = Convert.ToByte(arr[i], 16);
}

// If the block is irregular there is the possibility TransformFinalBlock will throw

var result = decryptorTransformer.TransformFinalBlock(encrypted2, 0, encrypted2.Length);

if (result.Length != sizeof(int))
{
    throw new Exception();
}

var id2 = BitConverter.ToInt32(result, 0);

for id = 123 we have an encoded id = 4E-CD-80-9E-7E-FB-A7-B9-74-B6-3A-37-57-9C-BD-A9. I could have made it shorter by using Base64 or by removing the -, but in the second case the code would be a little more difficult. Without the -: D2B4F51E6577967A2262E3AE51F3EC74, in Base64: 0rT1HmV3lnoiYuOuUfPsdA==

Considering your use, probably DES is secure enough. With DES the id would be:

F2-54-4B-CE-23-83-96-C2 // With -
F2544BCE238396C2 // Without -
8lRLziODlsI= // Base64

To use DES change all the Aes to DES and remove the BlockSize and KeySize lines.

Upvotes: 3

Salvatore Previti
Salvatore Previti

Reputation: 9050

If I understood correctly your question, id is client id.

If you don't want to show your ID at all the solution is to not use a numeric id and do queries directly by client name. This is a little slower indeed but not so slow. You can get the id with a "reverse" query by client name, you can index by client name.

One possibility to avoid too much queries by username is to store the id in session or in an hidden field in a form using post (you can mix http post and http get without too much problems). You can store two fields: client name and client id, if client name match with the one in http get, you don't need to fetch the id. If they don't match, you can query the db for the id. The idea is to cache the id, so you search the id by client only once.

Upvotes: 2

Loki Kriasus
Loki Kriasus

Reputation: 1301

If you want the result to be deterministic you have to pass some unique combination of parameters. In your case, you could use the "customername" parameter with some number after it for customers with same name (you will have to store that number in your db along with the customer name). For example:

localhost/customer/Aaron_Babichev - for the first customer with name Aaron Babichev
localhost/customer/Aaron_Babichev_2 - for the second customer with name Aaron Babichev
...

Your route mask would be something like customer/{customername}_{customerIndex}/.

Upvotes: 0

Related Questions