首先 session 和 cache 拥有各自的优势而存在.他们的优劣就不在这里讨论了. 以下类实现了 使用加密cookie代替session验证用户登录状态 支持 1小时/1周 有效期2种模式 (期间有新的请求则更新失效时间)
vs2010项目(同样适合05,08项目) 源码下载地址http://www.370b.com/bbsx/cookie-login/cookie.rar在自定义字符CustomCode 不被知道的情况下 该加密过程是相对安全的. 你还可以更改其中 的 2处MD5哈希值 生成的方式、DEChar(ENChar)混淆字符 让代码更与众不同
调用方式
- Dim user As New Rayyu.User() '初始化用户信息(检测当前请求用户是否登录)
- If user.Online Then
- Response.Write("<br />name:" & user.Name & ",online:" & user.Online & ",id:" & user.ID)
- End If
-
-
- Dim user2 As New Rayyu.User(1, "用户名", False) ‘初始化(写入新用户)
复制代码
vb code:
- Imports System.Web
- Imports System.Text.RegularExpressions
- Imports System.Text
- Imports System.Security.Cryptography
- ''' <summary>
- ''' 用户登录机制 支持1小时/1周状态
- ''' </summary>
- ''' <remarks></remarks>
- Public Class User
- #Region "自定义参数"
- ''' <summary>
- ''' 自定义字符 用于第一层加解密密匙
- ''' </summary>
- ''' <remarks></remarks>
- Private Const CustomCode As String = "QQ:867863456"
- ''' <summary>
- ''' cookie名
- ''' </summary>
- ''' <remarks></remarks>
- Private Const CookieName As String = "userinfo"
- ''' <summary>
- ''' Cookie作用域
- ''' </summary>
- ''' <remarks></remarks>
- Private Const CookieDomain As String = ".370b.com"
- ''' <summary>
- ''' 编码
- ''' </summary>
- ''' <remarks></remarks>
- Private Shared Encoder As Encoding = Encoding.UTF8
- ''' <summary>
- ''' 用户名的正则检测 我的是:首位由字母或者汉字构成,由字母、数字、下划线、和汉字的 2-20位的字符 组合而成 的
- ''' </summary>
- ''' <remarks></remarks>
- Private Const RegexUserName As String = "[a-zA-Z\u4e00-\u9fa5][\w\u4e00-\u9fa5]{1,19}"
- ''' <summary>
- ''' 区域化信息设置
- ''' </summary>
- ''' <remarks></remarks>
- Private Shared ReadOnly Format As Globalization.CultureInfo = New System.Globalization.CultureInfo("zh-CN", True)
- #End Region
- #Region "回调参数"
- ''' <summary>
- ''' 是否在线
- ''' </summary>
- ''' <remarks></remarks>
- Public ReadOnly Property Online As Boolean
- Get
- Return _Online
- End Get
- End Property
- Private _Online As Boolean = False
- ''' <summary>
- ''' 用户ID (Online=true情况下使用)
- ''' </summary>
- ''' <remarks></remarks>
- Public ReadOnly Property Id As Integer
- Get
- Return _Id
- End Get
- End Property
- Private _Id As Integer
- ''' <summary>
- ''' 用户名 (Online=true情况下使用)
- ''' </summary>
- ''' <remarks></remarks>
- Public ReadOnly Property Name As String
- Get
- Return _Name
- End Get
- End Property
- Private _Name As String
- ''' <summary>
- ''' 有效期是否为7天
- ''' </summary>
- ''' <remarks></remarks>
- Public ReadOnly Property IsWeek As Boolean
- Get
- Return _IsWeek
- End Get
- End Property
- Private ReadOnly _IsWeek As Boolean
- #End Region
- ''' <summary>
- ''' 初始化用户信息(检测当前请求用户是否登录)
- ''' </summary>
- ''' <remarks></remarks>
- Public Sub New()
- '读取cookie
- Dim cookie As HttpCookie = HttpContext.Current.Request.Cookies(CookieName)
- If cookie IsNot Nothing Then
- '存在cookie
- Dim value As String = cookie.Values("u"), key As String = cookie.Values("i"), tname As String = cookie.Values("n")
- cookie = Nothing
- If tname IsNot Nothing AndAlso value IsNot Nothing AndAlso key IsNot Nothing AndAlso Regex.IsMatch(key, "^[1-8A-H]{2}(-[1-8A-H]{2}){7}$", Text.RegularExpressions.RegexOptions.None) Then
- '存在对应键值
- Dim keybyte As Byte() = toByte(DEChar(key)) '解密密匙的后8位字节 由参数i构成
- If keybyte IsNot Nothing Then
- Dim autocode() As Byte '解密密匙的前16位字节 由用户UserAgent,用户名,自定义字符 组合而成 的 md5
- Using m As New System.Security.Cryptography.MD5CryptoServiceProvider()
- autocode = m.ComputeHash(Encoder.GetBytes(String.Format(Format, "{0}_{2}_{1}", HttpContext.Current.Request.UserAgent, tname, CustomCode)))
- m.Clear()
- End Using
- Dim keyboard() As Byte = New Byte(keybyte.Length + autocode.Length - 1) {}
- autocode.CopyTo(keyboard, 0)
- keybyte.CopyTo(keyboard, autocode.Length)
- value = DesDecrypt(value, keyboard)
- If value.Length > 0 Then
- '解密成功 第一层合法
- Dim values As Match = Regex.Match(value, "^(?<md5>[\w]{32})(?<isweek>[01])(?<id>[\d]{1,10})(?<name>" & RegexUserName & ")\|(?<exp>[\d]{1,19})$")
- If values.Success Then
- Dim LostDateTime As Long
- If Integer.TryParse(values.Groups("id").Value, Me._Id) AndAlso Me._Id > 0 AndAlso Long.TryParse(values.Groups("exp").Value, LostDateTime) AndAlso LostDateTime > 0 Then
- '解密后的字符串格式正确
- Me._IsWeek = (values.Groups("isweek").Value = "1")
- '此md5用于验证解密后的字符串 由用户id,用户名,cookie写入时间,自定义字符串 以及有效期是否是1周 组合
- Dim md5 As String = MD5Public(String.Format(Format, "{0}{5}{1}{2}:rayyu.{3};{4}", values.Groups("id").Value, values.Groups("exp").Value, values.Groups("name").Value, CookieDomain, IsWeek, CustomCode))
- If md5 = values.Groups("md5").Value Then
- 'md5正常
- Dim lostdate As Double = (Now - New DateTime(LostDateTime)).TotalMinutes
- Dim l_a As Integer
- If IsWeek Then
- l_a = 10080
- Else
- l_a = 60
- End If
- If lostdate > 0 AndAlso lostdate < l_a Then
- 'cookie在有效期内
- Me._Name = values.Groups("name").Value
- Me._Online = True
- If lostdate > 15 Then
- 'cookie以写入超过15分钟,从新写入1次cookie
- SetUser(Me._Id, Me._Name, Me._IsWeek, autocode)
- End If
- End If
- Else
- Me._Id = 0
- Me._Name = Nothing
- End If
- End If
- End If
- End If
- End If
- End If
- End If
- End Sub
- ''' <summary>
- ''' 初始化(写入新用户)
- ''' </summary>
- ''' <param name="userid">用户id</param>
- ''' <param name="username">用户名</param>
- ''' <param name="isweek">是否保持一周登录状态</param>
- ''' <remarks></remarks>
- Public Sub New(ByVal userId As Integer, ByVal userName As String, ByVal isWeek As Boolean)
- SetUser(userId, userName, isWeek)
- Me._ID = userId
- Me._Name = userName
- Me._IsWeek = isWeek
- Me._Online = True
- End Sub
- ''' <summary>
- ''' 写入用户
- ''' </summary>
- ''' <param name="userid">用户id</param>
- ''' <param name="username">用户名</param>
- ''' <param name="isweek">是否保持一周登录状态</param>
- ''' <param name="autocode"></param>
- ''' <remarks></remarks>
- Private Shared Sub SetUser(ByVal userid As Integer, ByVal username As String, ByVal isweek As Boolean, Optional ByVal autocode As Byte() = Nothing)
- If autocode Is Nothing Then
- '解密密匙的前16位字节 由用户UserAgent,用户名,自定义字符 组合而成 的 md5
- Using m As New System.Security.Cryptography.MD5CryptoServiceProvider()
- autocode = m.ComputeHash(Encoder.GetBytes(String.Format(Format, "{0}_{2}_{1}", HttpContext.Current.Request.UserAgent, username, CustomCode)))
- End Using
- End If
- Dim expires As DateTime
- Dim isweekint As Char
- If isweek Then
- expires = Now.AddDays(7)
- isweekint = "1"
- Else
- expires = Now.AddHours(1)
- isweekint = "0"
- End If
- '解密密匙的后8位字节 随机生成参数i
- Dim rbyte() As Byte = Encoder.GetBytes(RandomCode(8))
- Dim keyboard() As Byte = New Byte(23) {}
- autocode.CopyTo(keyboard, 0)
- '组合密匙 长度为24位
- rbyte.CopyTo(keyboard, autocode.Length)
- autocode = Nothing
- Dim exp As String = Now.Ticks.ToString("D", Format)
- '加密字符串
- Dim value As String = DesEncrypt(String.Format(Format, "{4}{0}{1}{2}|{3}", isweekint, userid, username, exp, MD5Public(String.Format(Format, "{0}{5}{1}{2}:rayyu.{3};{4}", userid, exp, username, CookieDomain, isweek, CustomCode))), keyboard)
- keyboard = Nothing
- Dim key As String = ENChar(System.BitConverter.ToString(rbyte)) '混淆参数i
- rbyte = Nothing
- '写入cookie
- Dim cookie As New HttpCookie(CookieName)
- cookie.Values.Add("n", username)
- cookie.Values.Add("u", value)
- cookie.Values.Add("i", key)
- cookie.Path = "/"
- cookie.Expires = expires
- cookie.Domain = CookieDomain
- HttpContext.Current.Response.Cookies.Set(cookie)
- End Sub
- ''' <summary>
- ''' TripleDESC解密
- ''' </summary>
- ''' <param name="strText">待解密字符串</param>
- ''' <param name="key">密匙</param>
- ''' <returns></returns>
- ''' <remarks></remarks>
- Protected Friend Shared Function DesDecrypt(ByVal strText As String, ByVal key As Byte()) As String
- Try
- Using provider As New System.Security.Cryptography.TripleDESCryptoServiceProvider()
- provider.Key = key
- provider.Mode = System.Security.Cryptography.CipherMode.ECB
- Dim inputBuffer As Byte() = Convert.FromBase64String(strText)
- Return Encoder.GetString(provider.CreateDecryptor().TransformFinalBlock(inputBuffer, 0, inputBuffer.Length)).Trim
- End Using
- Catch ex As CryptographicException
- Return String.Empty
- Catch ex As ArgumentNullException
- Return String.Empty
- Catch ex As DecoderFallbackException
- Return String.Empty
- Catch ex As ArgumentException
- Return String.Empty
- Catch ex As FormatException
- Return String.Empty
- End Try
- End Function
- ''' <summary>
- ''' TripleDESC加密
- ''' </summary>
- ''' <param name="strText">待加密字符串</param>
- ''' <param name="key">密匙</param>
- ''' <returns></returns>
- ''' <remarks></remarks>
- Protected Friend Shared Function DesEncrypt(ByVal strText As String, ByVal key As Byte()) As String
- Try
- Using provider As New System.Security.Cryptography.TripleDESCryptoServiceProvider()
- provider.Key = key
- provider.Mode = System.Security.Cryptography.CipherMode.ECB
- Dim bytes As Byte() = Encoder.GetBytes(strText)
- Return Convert.ToBase64String(provider.CreateEncryptor().TransformFinalBlock(bytes, 0, bytes.Length))
- End Using
- Catch ex As CryptographicException
- Return String.Empty
- Catch ex As ArgumentNullException
- Return String.Empty
- Catch ex As DecoderFallbackException
- Return String.Empty
- Catch ex As ArgumentException
- Return String.Empty
- Catch ex As FormatException
- Return String.Empty
- End Try
- End Function
- ''' <summary>
- ''' md5加密
- ''' </summary>
- ''' <param name="str">待加密字符串</param>
- ''' <returns>返回加密后字符串</returns>
- ''' <remarks></remarks>
- Private Shared Function MD5Public(ByVal str As String) As String
- Dim returnx As String = "0000000000000000"
- If str IsNot Nothing AndAlso str IsNot String.Empty Then
- Try
- Using m As New System.Security.Cryptography.MD5CryptoServiceProvider()
- Dim MDByte As Byte() = m.ComputeHash(Encoder.GetBytes(str))
- returnx = Strings.Replace(System.BitConverter.ToString(MDByte), "-", "")
- m.Clear()
- End Using
- Catch ex As ObjectDisposedException
- returnx = "0000000000000000"
- Catch ex As ArgumentOutOfRangeException
- returnx = "0000000000000003"
- Catch ex As ArgumentNullException
- returnx = "0000000000000001"
- Catch ex As EncoderFallbackException
- returnx = "0000000000000001"
- Catch ex As InvalidOperationException
- returnx = "0000000000000002"
- End Try
- End If
- Return returnx
- End Function
- ''' <summary>
- ''' 随机数
- ''' </summary>
- ''' <remarks></remarks>
- Private Shared Randoms As New Random
- ''' <summary>
- ''' 随机字符集合
- ''' </summary>
- ''' <remarks></remarks>
- Private Shared xarrChar() As Char = New Char() {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}
- ''' <summary>
- ''' 生成随机数
- ''' </summary>
- ''' <returns></returns>
- ''' <remarks></remarks>
- Public Shared Function RandomCode(ByVal length As Integer) As String
- Dim str As String = ""
- Dim mlength As Integer = xarrChar.Length
- For i As Integer = 0 To length - 1
- str &= xarrChar(Randoms.Next(0, mlength))
- Next
- Return str
- End Function
- ''' <summary>
- ''' 16进制字符串转Byte数组
- ''' </summary>
- ''' <param name="value"></param>
- ''' <returns></returns>
- ''' <remarks></remarks>
- Private Shared Function toByte(ByVal value As String) As Byte()
- Try
- Dim chars As String() = value.Split("-")
- Dim length As Integer = chars.Length - 1
- Dim byte_() As Byte = New Byte(length) {}
- For i As Integer = 0 To length
- byte_(i) = Convert.ToByte(chars(i), 16)
- Next
- Return byte_
- Catch ex As ArgumentException
- Return Nothing
- Catch ex As FormatException
- Return Nothing
- Catch ex As OverflowException
- Return Nothing
- End Try
- End Function
- ''' <summary>
- ''' TripleDESC-部分密匙 字符混淆 如果要修改下面的字符 请注意修改上面的正则
- ''' </summary>
- ''' <param name="value"></param>
- ''' <returns></returns>
- ''' <remarks></remarks>
- Private Shared Function ENChar(ByVal value As String) As String
- value = Strings.Replace(value, "A", "H")
- value = Strings.Replace(value, "B", "G")
- value = Strings.Replace(value, "0", "B")
- value = Strings.Replace(value, "9", "A")
- Return value
- End Function
- ''' <summary>
- ''' TripleDESC-部分密匙 字符反混淆 如果要修改下面的字符 请注意修改上面的正则
- ''' </summary>
- ''' <param name="value"></param>
- ''' <returns></returns>
- ''' <remarks></remarks>
- Private Shared Function DEChar(ByVal value As String) As String
- value = Strings.Replace(value, "A", "9")
- value = Strings.Replace(value, "B", "0")
- value = Strings.Replace(value, "G", "B")
- value = Strings.Replace(value, "H", "A")
- Return value
- End Function
- End Class
复制代码
|