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));
}
}
}