源码来自MVC4
@Html.AntiForgeryToken() 源码分析
public MvcHtmlString AntiForgeryToken() { return new MvcHtmlString(AntiForgery.GetHtml().ToString()); }
AntiForgery源自System.Web.Helpers.AntiForgery
public static HtmlString GetHtml() { if (HttpContext.Current == null) { throw new ArgumentException(WebPageResources.HttpContextUnavailable); } TagBuilder formInputElement = AntiForgery._worker.GetFormInputElement(new HttpContextWrapper(HttpContext.Current)); return formInputElement.ToHtmlString(TagRenderMode.SelfClosing); }
//查到_worker的创建
private static readonly AntiForgeryWorker _worker = AntiForgery.CreateSingletonAntiForgeryWorker();
//发现IAntiForgeryTokenSerializer来自AntiForgeryTokenSerializer
//而且发现用所以接口的实例对象,开始查看具体代码实现
private static AntiForgeryWorker CreateSingletonAntiForgeryWorker() { ICryptoSystem cryptoSystem = MachineKey45CryptoSystem.Instance; if (cryptoSystem == null) { cryptoSystem = new MachineKey40CryptoSystem(); } IAntiForgeryConfig config = new AntiForgeryConfigWrapper(); IAntiForgeryTokenSerializer serializer = new AntiForgeryTokenSerializer(cryptoSystem); ITokenStore tokenStore = new AntiForgeryTokenStore(config, serializer); IClaimUidExtractor claimUidExtractor = new ClaimUidExtractor(config, ClaimsIdentityConverter.Default); ITokenValidator validator = new TokenValidator(config, claimUidExtractor); return new AntiForgeryWorker(serializer, config, tokenStore, validator); }
//_worker的GetFormInputElement,发现value是_serializer.Serialize序列出来的,于是查看AntiForgeryTokenSerializer对象
public TagBuilder GetFormInputElement(HttpContextBase httpContext) { this.CheckSSLConfig(httpContext); AntiForgeryToken cookieTokenNoThrow = this.GetCookieTokenNoThrow(httpContext); AntiForgeryToken antiForgeryToken; AntiForgeryToken token; this.GetTokens(httpContext, cookieTokenNoThrow, out antiForgeryToken, out token); if (antiForgeryToken != null) { this._tokenStore.SaveCookieToken(httpContext, antiForgeryToken); } TagBuilder tagBuilder = new TagBuilder("input"); tagBuilder.Attributes["type"] = "hidden"; tagBuilder.Attributes["name"] = this._config.FormFieldName; tagBuilder.Attributes["value"] = this._serializer.Serialize(token); return tagBuilder; }
//查到AntiForgeryTokenSerializer对象的Serialize函数
public string Serialize(AntiForgeryToken token) { string result; using (MemoryStream memoryStream = new MemoryStream()) { using (BinaryWriter binaryWriter = new BinaryWriter(memoryStream)) { binaryWriter.Write(1); binaryWriter.Write(token.SecurityToken.GetData()); binaryWriter.Write(token.IsSessionToken); if (!token.IsSessionToken) { if (token.ClaimUid != null) { binaryWriter.Write(true); binaryWriter.Write(token.ClaimUid.GetData()); } else { binaryWriter.Write(false); binaryWriter.Write(token.Username); } binaryWriter.Write(token.AdditionalData); } binaryWriter.Flush(); result = this._cryptoSystem.Protect(memoryStream.ToArray()); } } return result; }
/关键的序列化函数
//产生疑惑token.SecurityToken.GetData(),这个数据哪里来的
//token.IsSessionToken这个是bool,看命名就知道是用来判断是不是生成关联session的token
//退回后查看AntiForgeryToken这个class
//
//发现这段 GetFormInputElement函数里面如此创建
AntiForgeryToken token;
this.GetTokens(httpContext, cookieTokenNoThrow, out antiForgeryToken, out token);
//通过上方查看_worker知道的实例
// ITokenStore tokenStore = new AntiForgeryTokenStore(config, serializer);
//查到
private void GetTokens(HttpContextBase httpContext, AntiForgeryToken oldCookieToken, out AntiForgeryToken newCookieToken, out AntiForgeryToken formToken) { newCookieToken = null; if (!this._validator.IsCookieTokenValid(oldCookieToken)) { AntiForgeryToken antiForgeryToken; newCookieToken = (antiForgeryToken = this._validator.GenerateCookieToken()); oldCookieToken = antiForgeryToken; } formToken = this._validator.GenerateFormToken(httpContext, AntiForgeryWorker.ExtractIdentity(httpContext), oldCookieToken); }
//继续追看
public AntiForgeryToken GenerateFormToken(HttpContextBase httpContext, IIdentity identity, AntiForgeryToken cookieToken) { AntiForgeryToken antiForgeryToken = new AntiForgeryToken { SecurityToken = cookieToken.SecurityToken, IsSessionToken = false//原来默认是false,暂时认为默认是不使用session的 }; bool flag = false; if (identity != null && identity.IsAuthenticated) { if (!this._config.SuppressIdentityHeuristicChecks) { flag = true; } antiForgeryToken.ClaimUid = this._claimUidExtractor.ExtractClaimUid(identity); if (antiForgeryToken.ClaimUid == null) { antiForgeryToken.Username = identity.Name; } } if (this._config.AdditionalDataProvider != null) { antiForgeryToken.AdditionalData = this._config.AdditionalDataProvider.GetAdditionalData(httpContext); } if (flag && string.IsNullOrEmpty(antiForgeryToken.Username) && antiForgeryToken.ClaimUid == null && string.IsNullOrEmpty(antiForgeryToken.AdditionalData)) { throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, WebPageResources.TokenValidator_AuthenticatedUserWithoutUsername, new object[] { identity.GetType() })); } return antiForgeryToken; }
//经过这样一看token的创建就清晰了
//接着查看token的token.SecurityToken这个属性
public BinaryBlob SecurityToken { get { if (this._securityToken == null) { this._securityToken = new BinaryBlob(128);//发现默认是128,对象是BinaryBlob } return this._securityToken; } set { this._securityToken = value; } }
//查看BinaryBlob的构造函数,出现一个GenerateNewToken函数
public BinaryBlob(int bitLength) : this(bitLength, BinaryBlob.GenerateNewToken(bitLength)) { }
//GenerateNewToken源码
private static byte[] GenerateNewToken(int bitLength) { byte[] array = new byte[bitLength / 8]; BinaryBlob._prng.GetBytes(array); return array; }
//该死,有出现一个未知的东西,_prng
private static readonly RNGCryptoServiceProvider _prng = new RNGCryptoServiceProvider();
[SecuritySafeCritical] public override void GetBytes(byte[] data) { if (data == null) { throw new ArgumentNullException("data"); } RNGCryptoServiceProvider.GetBytes(this.m_safeProvHandle, data, data.Length); } [SecurityCritical, SuppressUnmanagedCodeSecurity] [DllImport("QCall", CharSet = CharSet.Unicode)] private static extern void GetBytes(SafeProvHandle hProv, byte[] randomBytes, int count);
//至此必应了一下RNGCryptoServiceProvider类(bing查msdn特别方便)
//https://msdn.microsoft.com/zh-cn/library/system.security.cryptography.rngcryptoserviceprovider(v=vs.110).aspx
//http://www.cnblogs.com/izanami/archive/2011/04/20/2022173.html
原来RNGCryptoServiceProvider的GetBytes用经过加密的强随机值序列填充字节数组,最终的随机数据生成!
//现在这段序列化的部分已经解开了一些了 binaryWriter.Write(1); binaryWriter.Write(token.SecurityToken.GetData());//数据明了,一段用经过加密的强随机值数组 binaryWriter.Write(token.IsSessionToken);//Bool判断是否使用session if (!token.IsSessionToken) { if (token.ClaimUid != null) { binaryWriter.Write(true); binaryWriter.Write(token.ClaimUid.GetData());//也是一个BinaryBlob } else { binaryWriter.Write(false); binaryWriter.Write(token.Username); } binaryWriter.Write(token.AdditionalData); } binaryWriter.Flush(); result = this._cryptoSystem.Protect(memoryStream.ToArray());
//继续解开ClaimUid
//在上文的 GenerateFormToken发现这样的一段
antiForgeryToken.ClaimUid = this._claimUidExtractor.ExtractClaimUid(identity);
//_claimUidExtractor在创建的地方是ClaimUidExtractor
//发现源码
public BinaryBlob ExtractClaimUid(IIdentity identity) { if (identity == null || !identity.IsAuthenticated || this._config.SuppressIdentityHeuristicChecks) { return null; } ClaimsIdentity claimsIdentity = this._claimsIdentityConverter.TryConvert(identity); if (claimsIdentity == null) { return null; } string[] uniqueIdentifierParameters = ClaimUidExtractor.GetUniqueIdentifierParameters(claimsIdentity, this._config.UniqueClaimTypeIdentifier); byte[] data = CryptoUtil.ComputeSHA256(uniqueIdentifierParameters); return new BinaryBlob(256, data); }
public static byte[] ComputeSHA256(IList<string> parameters) { byte[] result; using (MemoryStream memoryStream = new MemoryStream()) { using (BinaryWriter binaryWriter = new BinaryWriter(memoryStream)) { foreach (string current in parameters) { binaryWriter.Write(current); } binaryWriter.Flush(); using (SHA256 sHA = CryptoUtil._sha256Factory()) { byte[] array = sHA.ComputeHash(memoryStream.GetBuffer(), 0, checked((int)memoryStream.Length)); result = array; } } } return result; }
//发现是SHA256的哈希计算值
//然后是AdditionalData
public string AdditionalData { get { return this._additionalData ?? string.Empty; } set { this._additionalData = value; } }
//最后是这句result = this._cryptoSystem.Protect(memoryStream.ToArray());
//MachineKey40CryptoSystem : ICryptoSystem
public string Protect(byte[] data) { byte[] array = new byte[data.Length + 4]; Buffer.BlockCopy(data, 0, array, 4, data.Length); array[0] = 133; array[1] = 135; array[2] = 242; array[3] = 102; string hex = this._encoder(array, MachineKeyProtection.All); return MachineKey40CryptoSystem.HexToBase64(hex); } internal static string HexToBase64(string hex) { int num = hex.Length / 2; byte[] array = new byte[num]; for (int i = 0; i < num; i++) { array[i] = (byte)((MachineKey40CryptoSystem.HexValue(hex[i * 2]) << 4) + MachineKey40CryptoSystem.HexValue(hex[i * 2 + 1])); } return HttpServerUtility.UrlTokenEncode(array); }
//将那些随机生成的数据变成了16进制字符串
//加密到此结束了
//最后就是对应的解密了
public AntiForgeryToken Deserialize(string serializedToken) { try { using (MemoryStream memoryStream = new MemoryStream(this._cryptoSystem.Unprotect(serializedToken))) { using (BinaryReader binaryReader = new BinaryReader(memoryStream)) { AntiForgeryToken antiForgeryToken = AntiForgeryTokenSerializer.DeserializeImpl(binaryReader); if (antiForgeryToken != null) { return antiForgeryToken; } } } } catch { } throw HttpAntiForgeryException.CreateDeserializationFailedException(); } private static AntiForgeryToken DeserializeImpl(BinaryReader reader) { byte b = reader.ReadByte();//从当前流中读取下一个字节,并使流的当前位置提升 1 个字节。 if (b != 1)//对应加密的binaryWriter.Write(1); { return null; } //依照加密时候的分段大小对应解密 AntiForgeryToken antiForgeryToken = new AntiForgeryToken(); byte[] data = reader.ReadBytes(16); antiForgeryToken.SecurityToken = new BinaryBlob(128, data); antiForgeryToken.IsSessionToken = reader.ReadBoolean(); if (!antiForgeryToken.IsSessionToken) { bool flag = reader.ReadBoolean(); if (flag) { byte[] data2 = reader.ReadBytes(32); antiForgeryToken.ClaimUid = new BinaryBlob(256, data2); } else { antiForgeryToken.Username = reader.ReadString(); } antiForgeryToken.AdditionalData = reader.ReadString(); } if (reader.BaseStream.ReadByte() != -1) { return null; } return antiForgeryToken; }
文章系转载 http://www.cnblogs.com/RainbowInTheSky/p/5565248.html