ฉันต้องการสร้างสตริงที่ไม่ซ้ำกันแบบสุ่มเช่นสตริงที่สร้างโดยไลบรารี MSDN ( Error Object ) ตัวอย่างเช่น ควรสร้างสตริงเช่น "t9zk6eay"
ฉันต้องการสร้างสตริงที่ไม่ซ้ำกันแบบสุ่มเช่นสตริงที่สร้างโดยไลบรารี MSDN ( Error Object ) ตัวอย่างเช่น ควรสร้างสตริงเช่น "t9zk6eay"
คำตอบ:
การใช้ Guid น่าจะเป็นวิธีที่ดี แต่เพื่อให้ได้สิ่งที่ดูเหมือนตัวอย่างของคุณคุณอาจต้องการแปลงเป็นสตริง Base64:
Guid g = Guid.NewGuid();
string GuidString = Convert.ToBase64String(g.ToByteArray());
GuidString = GuidString.Replace("=","");
GuidString = GuidString.Replace("+","");
ฉันกำจัด "=" และ "+" เพื่อเข้าใกล้ตัวอย่างของคุณอีกเล็กน้อยมิฉะนั้นคุณจะได้ "==" ที่ส่วนท้ายของสตริงและมี "+" ตรงกลาง นี่คือสตริงเอาต์พุตตัวอย่าง:
"OZVV5TpP4U6wJthaCORZEQ"
new Guid()
โดยไม่ต้อง "แฮ็ก" (การปลอมแปลงนาฬิกาหรือโครงสร้างข้อมูลภายในของ Windows) อย่าลังเลที่จะใช้คอร์เธรดไพรเมอร์ซิงโครไนซ์และอื่น ๆ ได้มากเท่าที่คุณต้องการ
อัปเดต 2016/1/23
หากคุณพบว่าคำตอบนี้มีประโยชน์คุณอาจสนใจห้องสมุดการสร้างรหัสผ่านแบบธรรมดา (~ 500 SLOC) ที่ฉันเผยแพร่ :
Install-Package MlkPwgen
จากนั้นคุณสามารถสร้างสตริงแบบสุ่มได้เช่นเดียวกับในคำตอบด้านล่าง:
var str = PasswordGenerator.Generate(length: 10, allowed: Sets.Alphanumerics);
ข้อดีอย่างหนึ่งของห้องสมุดคือว่ารหัสเป็นปัจจัยที่ดีกว่าออกเพื่อให้คุณสามารถใช้การสุ่มที่เชื่อถือได้มากขึ้นกว่าการสร้างสตริง ตรวจสอบไซต์โครงการเพื่อดูรายละเอียดเพิ่มเติม
เนื่องจากยังไม่มีใครให้รหัสความปลอดภัยฉันจึงโพสต์สิ่งต่อไปนี้เผื่อว่าใครพบว่ามีประโยชน์
string RandomString(int length, string allowedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") {
if (length < 0) throw new ArgumentOutOfRangeException("length", "length cannot be less than zero.");
if (string.IsNullOrEmpty(allowedChars)) throw new ArgumentException("allowedChars may not be empty.");
const int byteSize = 0x100;
var allowedCharSet = new HashSet<char>(allowedChars).ToArray();
if (byteSize < allowedCharSet.Length) throw new ArgumentException(String.Format("allowedChars may contain no more than {0} characters.", byteSize));
// Guid.NewGuid and System.Random are not particularly random. By using a
// cryptographically-secure random number generator, the caller is always
// protected, regardless of use.
using (var rng = System.Security.Cryptography.RandomNumberGenerator.Create()) {
var result = new StringBuilder();
var buf = new byte[128];
while (result.Length < length) {
rng.GetBytes(buf);
for (var i = 0; i < buf.Length && result.Length < length; ++i) {
// Divide the byte into allowedCharSet-sized groups. If the
// random value falls into the last group and the last group is
// too small to choose from the entire allowedCharSet, ignore
// the value in order to avoid biasing the result.
var outOfRangeStart = byteSize - (byteSize % allowedCharSet.Length);
if (outOfRangeStart <= buf[i]) continue;
result.Append(allowedCharSet[buf[i] % allowedCharSet.Length]);
}
}
return result.ToString();
}
}
ขอขอบคุณ Ahmad ที่ชี้ให้เห็นวิธีการทำให้โค้ดทำงานบน. NET Core
.netcore
: แทนที่var rng = new RNGCryptoServiceProvider()
ด้วยvar rng = RandomNumberGenerator.Create()
ฉันจะเตือนว่า guid ของมีไม่ได้ตัวเลขสุ่ม ไม่ควรใช้เป็นพื้นฐานในการสร้างสิ่งที่คุณคาดว่าจะสุ่มโดยสิ้นเชิง (ดูhttp://en.wikipedia.org/wiki/Globally_Unique_Identifier ):
Cryptanalysis ของตัวสร้าง WinAPI GUID แสดงให้เห็นว่าเนื่องจากลำดับของ V4 GUID เป็นแบบสุ่มหลอกเนื่องจากสถานะเริ่มต้นเราสามารถทำนายได้ถึง 250,000 GUID ถัดไปที่ส่งคืนโดยฟังก์ชัน UuidCreate นี่คือเหตุผลที่ไม่ควรใช้ GUID ในการเข้ารหัสเช่นเป็นคีย์แบบสุ่ม
ให้ใช้วิธีสุ่ม C # แทน สิ่งนี้ ( พบรหัสที่นี่ ):
private string RandomString(int size)
{
StringBuilder builder = new StringBuilder();
Random random = new Random();
char ch ;
for(int i=0; i<size; i++)
{
ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65))) ;
builder.Append(ch);
}
return builder.ToString();
}
GUID เป็นสิ่งที่ดีหากคุณต้องการสิ่งที่ไม่เหมือนใคร (เช่นชื่อไฟล์ที่ไม่ซ้ำกันหรือคีย์ในฐานข้อมูล) แต่ไม่ดีสำหรับบางสิ่งที่คุณต้องการสุ่ม (เช่นรหัสผ่านหรือคีย์เข้ารหัส) ขึ้นอยู่กับใบสมัครของคุณ
แก้ไข . Microsoft กล่าวว่า Random ก็ไม่ได้ยอดเยี่ยมเช่นกัน ( http://msdn.microsoft.com/en-us/library/system.random(VS.71).aspx ):
ในการสร้างหมายเลขสุ่มที่ปลอดภัยด้วยการเข้ารหัสที่เหมาะสมสำหรับการสร้างรหัสผ่านแบบสุ่มตัวอย่างเช่นใช้คลาสที่ได้มาจาก System.Security.Cryptography.RandomNumberGenerator เช่น System.Security.Cryptography.RNGCryptoServiceProvider
ฉันทำให้โซลูชัน @Michael Kropats ง่ายขึ้นและสร้างเวอร์ชัน LINQ-esque
string RandomString(int length, string alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
{
var outOfRange = byte.MaxValue + 1 - (byte.MaxValue + 1) % alphabet.Length;
return string.Concat(
Enumerable
.Repeat(0, int.MaxValue)
.Select(e => RandomByte())
.Where(randomByte => randomByte < outOfRange)
.Take(length)
.Select(randomByte => alphabet[randomByte % alphabet.Length])
);
}
byte RandomByte()
{
using (var randomizationProvider = new RNGCryptoServiceProvider())
{
var randomBytes = new byte[1];
randomizationProvider.GetBytes(randomBytes);
return randomBytes.Single();
}
}
ฉันไม่คิดว่ามันเป็นแบบสุ่มจริงๆ แต่ฉันเดาว่ามันเป็นแฮช
เมื่อใดก็ตามที่ฉันต้องการตัวระบุแบบสุ่มฉันมักจะใช้ GUID และแปลงเป็นการแสดง "เปล่า":
Guid.NewGuid().ToString("n");
ลองผสมผสานระหว่าง Guid และ Time.Ticks
var randomNumber = Convert.ToBase64String(Guid.NewGuid().ToByteArray()) + DateTime.Now.Ticks;
randomNumber = System.Text.RegularExpressions.Regex.Replace(randomNumber, "[^0-9a-zA-Z]+", "");
ฉันแปลกใจว่าทำไมไม่มีโซลูชัน CrytpoGraphic GUID จะไม่ซ้ำกัน แต่ไม่ปลอดภัยเข้ารหัส ดู Dotnet Fiddle นี้
var bytes = new byte[40]; // byte size
using (var crypto = new RNGCryptoServiceProvider())
crypto.GetBytes(bytes);
var base64 = Convert.ToBase64String(bytes);
Console.WriteLine(base64);
ในกรณีที่คุณต้องการนำหน้าด้วย Guid:
var result = Guid.NewGuid().ToString("N") + base64;
Console.WriteLine(result);
สตริงตัวอักษรและตัวเลขที่สะอาดกว่า:
result = Regex.Replace(result,"[^A-Za-z0-9]","");
Console.WriteLine(result);
โซลูชัน Michael Kropats ใน VB.net
Private Function RandomString(ByVal length As Integer, Optional ByVal allowedChars As String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") As String
If length < 0 Then Throw New ArgumentOutOfRangeException("length", "length cannot be less than zero.")
If String.IsNullOrEmpty(allowedChars) Then Throw New ArgumentException("allowedChars may not be empty.")
Dim byteSize As Integer = 256
Dim hash As HashSet(Of Char) = New HashSet(Of Char)(allowedChars)
'Dim hash As HashSet(Of String) = New HashSet(Of String)(allowedChars)
Dim allowedCharSet() = hash.ToArray
If byteSize < allowedCharSet.Length Then Throw New ArgumentException(String.Format("allowedChars may contain no more than {0} characters.", byteSize))
' Guid.NewGuid and System.Random are not particularly random. By using a
' cryptographically-secure random number generator, the caller is always
' protected, regardless of use.
Dim rng = New System.Security.Cryptography.RNGCryptoServiceProvider()
Dim result = New System.Text.StringBuilder()
Dim buf = New Byte(128) {}
While result.Length < length
rng.GetBytes(buf)
Dim i
For i = 0 To buf.Length - 1 Step +1
If result.Length >= length Then Exit For
' Divide the byte into allowedCharSet-sized groups. If the
' random value falls into the last group and the last group is
' too small to choose from the entire allowedCharSet, ignore
' the value in order to avoid biasing the result.
Dim outOfRangeStart = byteSize - (byteSize Mod allowedCharSet.Length)
If outOfRangeStart <= buf(i) Then
Continue For
End If
result.Append(allowedCharSet(buf(i) Mod allowedCharSet.Length))
Next
End While
Return result.ToString()
End Function
สิ่งนี้เหมาะสำหรับฉัน
private string GeneratePasswordResetToken()
{
string token = Guid.NewGuid().ToString();
var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(token);
return Convert.ToBase64String(plainTextBytes);
}
นี้ได้รับการขอภาษาต่างๆ นี่คือคำถามหนึ่งข้อเกี่ยวกับรหัสผ่านที่ควรใช้ที่นี่เช่นกัน
หากคุณต้องการใช้สตริงสำหรับการย่อ URL คุณจะต้องมีพจนานุกรม <> หรือฐานข้อมูลเพื่อตรวจสอบว่ามีการใช้ ID ที่สร้างขึ้นแล้วหรือไม่
หากคุณต้องการสตริงตัวอักษรและตัวเลขที่มีตัวพิมพ์เล็กและตัวอักษรที่ตัวพิมพ์ใหญ่ ([a-zA-Z0-9]) คุณสามารถใช้ Convert ToBase64String () สำหรับวิธีแก้ปัญหาที่รวดเร็วและง่ายดาย
สำหรับความเป็นเอกลักษณ์ให้ตรวจสอบปัญหาวันเกิดเพื่อคำนวณว่าจะมีการจัดเรียง (A) ความยาวของสตริงที่สร้างขึ้นและ (B) จำนวนสตริงที่สร้างขึ้น
Random random = new Random();
int outputLength = 10;
int byteLength = (int)Math.Ceiling(3f / 4f * outputLength); // Base64 uses 4 characters for every 3 bytes of data; so in random bytes we need only 3/4 of the desired length
byte[] randomBytes = new byte[byteLength];
string output;
do
{
random.NextBytes(randomBytes); // Fill bytes with random data
output = Convert.ToBase64String(randomBytes); // Convert to base64
output = output.Substring(0, outputLength); // Truncate any superfluous characters and/or padding
} while (output.Contains('/') || output.Contains('+')); // Repeat if we contain non-alphanumeric characters (~25% chance if length=10; ~50% chance if length=20; ~35% chance if length=32)
รับคีย์เฉพาะโดยใช้รหัสแฮช GUID
public static string GetUniqueKey(int length)
{
string guidResult = string.Empty;
while (guidResult.Length < length)
{
// Get the GUID.
guidResult += Guid.NewGuid().ToString().GetHashCode().ToString("x");
}
// Make sure length is valid.
if (length <= 0 || length > guidResult.Length)
throw new ArgumentException("Length must be between 1 and " + guidResult.Length);
// Return the first length bytes.
return guidResult.Substring(0, length);
}
string randoms = Guid.NewGuid().ToString().Replace("-", string.Empty).Replace("+", string.Empty).Substring(0, 4);
ดูเพิ่มเติมได้ที่นี่