using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Grass.Authorize { /// <summary> /// 二进制授权帮助类,最多支持 62 种不同权限,鉴权值最大为2的62次方(即:4611686018427387904) /// </summary> public class BinAuth { /// <summary> /// 验证非负正整数是否为2的幂级 /// </summary> /// <remarks></remarks> /// <param name="n"></param> /// <returns></returns> public static bool IsBinPower(long n) { /* 判断是2的幂,1个数乘以2就是将该数左移1位,而2的0次幂为1, 所以2的n次幂(就是2的0次幂n次乘以2)就是将1左移n位, 这样我们知道如果一个数n是2的幂,则其只有首位为1, 其后若干个0,必然有n & (n - 1)为0。(在求1个数的二进制表示中1的个数的时候说过 ,n&(n-1)去掉n的最后一个1)。因此,判断一个数n是否为2的幂,只需要判断n&(n-1)是否为0即可。 */ return (n & (n - 1)) == 0; } /// <summary> /// 获取2 的 x 次方值 /// </summary> /// <param name="x">x 次方值</param> /// <returns></returns> public static long GetBinPower(int x) { return (long)System.Math.Pow(2, x); } /// <summary> /// 将数值转为等值2进制数 /// </summary> /// <param name="n"></param> /// <returns></returns> public static string GetBin(long n) { return Convert.ToString(n, 2); } /// <summary> /// 生成鉴权码 /// </summary> /// <param name="arr">权限值(2的幂级)</param> /// <remarks>每个鉴权值执行或操作(code = code | n)</remarks> /// <returns></returns> public static long GenAuthCode(params long[] arr) { if (arr == null) throw new Exception("权限值数组不允许为空,Grass.BinAuth.GenAuthCode()"); long code = 0; arr.ToList().ForEach(x => { if (!IsBinPower(x)) throw new Exception(string.Format("值 {0} 为无效的鉴权码不是2的幂级", x)); if (x< 0 ||x > 4611686018427387904) throw new Exception(string.Format("鉴权值 {0} 应大于 0 小于 4611686018427387904", x)); code = code | x; }); return code; } /// <summary> /// 添加权限 /// </summary> /// <param name="authCode">鉴权码</param> /// <param name="auth">权限值(2的幂级)</param> /// <remarks>code = authCode | auth</remarks> /// <returns></returns> public static long AddAuth(long authCode,long auth) { if (!IsBinPower(auth)) throw new Exception(string.Format("值 {0} 为无效的鉴权码不是2的幂级", auth)); if (auth < 0 || auth > 4611686018427387904) throw new Exception(string.Format("鉴权值 {0} 应大于 0 小于 4611686018427387904", auth)); long code = authCode | auth; return code; } /// <summary> /// 移除权限 /// </summary> /// <param name="authCode">鉴权码</param> /// <param name="auth">权限值(2的幂级)</param> /// <remarks>code = authCode & (~auth)</remarks> /// <returns></returns> public static long RemoveAuth(long authCode, long auth) { if (!IsBinPower(auth)) throw new Exception(string.Format("值 {0} 为无效的鉴权码不是2的幂级", auth)); if (auth < 0 || auth > 4611686018427387904) throw new Exception(string.Format("鉴权值 {0} 应大于 0 小于 4611686018427387904", auth)); long code = authCode & (~auth); return code; } /// <summary> /// 验证权限 /// </summary> /// <param name="authCode">鉴权码</param> /// <param name="auth">权限值(2的幂级)</param> /// <remarks>auth == (authCode & auth)</remarks> /// <returns></returns> public static bool IsHasAuth(long authCode, long auth) { if (!IsBinPower(auth)) throw new Exception(string.Format("值 {0} 为无效的鉴权码不是2的幂级", auth)); if (authCode <= 0 || auth<=0) return false; return auth == (authCode & auth); } } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Grass.Authorize; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace TestGrass { [TestClass] public class TestBinAuth { /// <summary> /// 验证非负正整数是否为 2 的幂级 /// </summary> /// <remarks> /// 判断是2的幂,1个数乘以2就是将该数左移1位,而2的0次幂为1, 所以2的n次幂(就是2的0次幂n次乘以2)就是将1左移n位, 这样我们知道如果一个数n是2的幂,则其只有首位为1,其后若干个0,必然有n & (n - 1)为0。(在求1个数的二进制表示中1的个数的时候说过,n&(n-1)去掉n的最后一个1)。因此,判断一个数n是否为2的幂,只需要判断n&(n-1)是否为0即可。 /// </remarks> /// <returns></returns> [TestMethod] public void TestIsBinPower() { string str = ""; for (int i = 0; i < 64; i++) { long n = BinAuth.GetBinPower(i); str = BinAuth.GetBin(n); if (!BinAuth.IsBinPower(n)) Assert.IsTrue(false); } Assert.IsTrue(true); } /// <summary> /// 获取2 的 x 次方值 /// </summary> /// <returns></returns> [TestMethod] public void TestGetBinPower() { long n = (long)Math.Pow(2, 50); string ns = BinAuth.GetBin(n); long m = BinAuth.GetBinPower(50); string ms = BinAuth.GetBin(m); Assert.IsTrue(n == m); } /// <summary> /// 将数值转为等值2进制数 /// </summary> /// <returns></returns> [TestMethod] public void TestGetBin() { long n = (long)Math.Pow(2, 50); string s1 = BinAuth.GetBin(n); string s2 = Convert.ToString(n, 2); Assert.IsTrue(s1.Equals(s2)); } /// <summary> /// 生成鉴权码 /// </summary> /// <param name="arr">权限值(2的幂级)</param> /// <remarks>每个鉴权值执行或操作</remarks> /// <returns></returns> [TestMethod] public void TestGenAuthCode() { long authCode = 0; string binStr = ""; List<long> codeList = new List<long>(); for (int i = 1; i <= 62; i++) { codeList.Add((long)Math.Pow(2, i)); } authCode = BinAuth.GenAuthCode(codeList.ToArray()); binStr = BinAuth.GetBin(authCode); ; Assert.IsTrue(true); } /// <summary> /// 添加权限 /// </summary> /// <remarks>code = authCode | auth</remarks> /// <returns></returns> [TestMethod] public void TestAddAuth() { long authCode = 0; string binStr = ""; for (int i = 1; i <= 62; i++) { long x = BinAuth.GetBinPower(i); authCode = BinAuth.AddAuth(authCode, x); binStr = BinAuth.GetBin(authCode); } binStr = BinAuth.GetBin(authCode); Assert.IsTrue(true); } /// <summary> /// 移除权限 /// </summary> /// <remarks>code = authCode & (~auth)</remarks> /// <returns></returns> [TestMethod] public void TestRemoveAuth() { long authCode = 9223372036854775806;//表示最大权限值 string binStr = ""; for (int i = 1; i <= 62; i++) { long x = BinAuth.GetBinPower(i); authCode = BinAuth.RemoveAuth(authCode, x); binStr = BinAuth.GetBin(authCode); } binStr = BinAuth.GetBin(authCode); Assert.IsTrue(true); } /// <summary> /// 验证权限 /// </summary> /// <returns></returns> [TestMethod] public void TestIsHasAuth() { long[] arr = {1, 2, 4, 8, 16, 32, 64}; long authCode = BinAuth.GenAuthCode(arr); Assert.IsTrue(BinAuth.IsHasAuth(authCode, 1)); Assert.IsTrue(BinAuth.IsHasAuth(authCode, 2)); Assert.IsTrue(BinAuth.IsHasAuth(authCode, 4)); Assert.IsTrue(BinAuth.IsHasAuth(authCode, 8)); Assert.IsTrue(BinAuth.IsHasAuth(authCode, 16)); Assert.IsTrue(BinAuth.IsHasAuth(authCode, 32)); Assert.IsTrue(BinAuth.IsHasAuth(authCode, 64)); Assert.IsFalse(BinAuth.IsHasAuth(-1, 0)); Assert.IsFalse(BinAuth.IsHasAuth(0, 0)); Assert.IsFalse(BinAuth.IsHasAuth(authCode, 128)); Assert.IsFalse(BinAuth.IsHasAuth(authCode, 256)); } } }