IBatis/IBatis.Net中的数据加密

 

<script type="text/javascript" src="http://www.cchensoft.com/gad/blog_csdn_article.js"></script>

作为一个o/r mapping组件,IBatis通过反射(Reflect)完成对象的持久化,
如果要对数据进行加密,那么切入点就在reflect上,
思路就是当IBatis通过Reflect给对象属性赋值时,我们解密数据,反之加密数据。

那么如何切入了?先跟踪源代码看看 :)

如何跟踪源代码这里就不繁述了,这里列出几个重要的对象/接口:

1. DotNetObjectDataExchange:顾名思义,对象数据交换类;
2. AccessorFactory:存取器工厂类;
3. ISetAccessorFactory/IGetAccessorFactory:set/get存取器工厂,对应属性的set/get操作;
4. ISetAccessor/IGetAccessor:set/get存取器;


显然上面几个对象/接口都是可切入的点,例如:
1. 用一个SecureObjectDataExchange去替换DotNetObjectDataExchange;
2. 实现自己的SetAccessorFactory/GetAccessorFactory对象;

切入点有了,那如何让IBatis调用了?也即如何注入到IBatis Runtime中呢?


我们知道IBatis对外的接口是ISqlMapper,而SqlMapper由DomSqlMapBuilder创建,
在DomSqlMapBuilder有两个属性就是我们需要的:
// Allow a custom ISetAccessorFactory to be set before configuration.
public ISetAccessorFactory SetAccessorFactory;

// Allow a custom IGetAccessorFactory to be set before configuration.
public IGetAccessorFactory GetAccessorFactory;


OK,现在万事俱备了,开始写代码:

step 1:
定制IGetAccessorFactory / ISetAccessorFactory;

    public class SecureGetAccessorFactory : IGetAccessorFactory
    {
        public IGetAccessor CreateGetAccessor(Type targetType, string name)
        {
            return new SecureGetAccessor(targetType, name);
        }
    }

    public class SecureSetAccessorFactory : ISetAccessorFactory
    {
        public ISetAccessor CreateSetAccessor(Type targetType, string name)
        {
            return new SecureSetAccessor(targetType, name);
        }
    }


step 2:
定制IGetAccessor / ISetAccessor

   public class SecureGetAccessor : IGetAccessor
    {
        private PropertyInfo _propertyInfo = null;
  private string _propertyName = string.Empty;
  private Type _targetType = null;
        private bool _isProtected = false;

        public SecureGetAccessor(Type targetType, string propertyName)
 {
  ReflectionInfo reflectionCache = ReflectionInfo.GetInstance( targetType );
            _propertyInfo = (PropertyInfo)reflectionCache.GetGetter(propertyName);

            object[] attrs = _propertyInfo.GetCustomAttributes(typeof(ProtectFieldAttribute), true);
            _isProtected = attrs.Length > 0;

            _targetType = targetType;
  _propertyName = propertyName;
 }

        #region IAccessor Members

        public string Name
        {
            get { return _propertyInfo.Name; }
        }

        public Type MemberType
        {
            get { return _propertyInfo.PropertyType; }
        }

        #endregion

        #region IGet Members

        public object Get(object target)
        {
            if (_propertyInfo.CanRead)
            {
                object ret = _propertyInfo.GetValue(target, null);
                if (_isProtected)
                {
                    // 加密
                    ret = SecureUtil.EncryptData(ret);
                }
                return ret;
            }
            else
            {
                throw new NotSupportedException(
                    string.Format("Property /"{0}/" on type "
                    + "{1} doesn't have a get method.", _propertyName, _targetType));
            }
        }

        #endregion
    }

    public class SecureSetAccessor : ISetAccessor
    {
        private PropertyInfo _propertyInfo = null;
  private string _propertyName = string.Empty;
  private Type _targetType = null;
        private bool _isProtected = false;

        public SecureSetAccessor(Type targetType, string propertyName)
 {
  ReflectionInfo reflectionCache = ReflectionInfo.GetInstance( targetType );
            _propertyInfo = (PropertyInfo)reflectionCache.GetGetter(propertyName);

            object[] attrs = _propertyInfo.GetCustomAttributes(typeof(ProtectFieldAttribute), true);
            _isProtected = attrs.Length > 0;

            _targetType = targetType;
  _propertyName = propertyName;
 }


        #region IAccessor Members

        public string Name
        {
            get { return _propertyInfo.Name; }
        }

        public Type MemberType
        {
            get { return _propertyInfo.PropertyType; }
        }

        #endregion

        #region IGet Members

        public void Set(object target, object value)
        {
            if (_propertyInfo.CanWrite)
            {
                if (_isProtected)
                {
                    // 解密
                    value = SecureUtil.DecryptData(value);
                }

                _propertyInfo.SetValue(target, value, null);
            }
            else
            {
                throw new NotSupportedException(
                    string.Format("Property /"{0}/" on type "
                    + "{1} doesn't have a set method.", _propertyName, _targetType));
            }
        }

        #endregion
    }


step 3:
注入IBatis runtime.

    DomSqlMapBuilder builder = new DomSqlMapBuilder();
    builder.SetAccessorFactory = new SecureSetAccessorFactory();
    builder.GetAccessorFactory = new SecureGetAccessorFactory();
    ISqlMapper mapper = builder.Configure("./sqlmap.config");


注:
ProtectFieldAttribute为一个Attribute,用于标明那些字段需要保护,
SecureUtil为一个加解密的对象,大家可用自己的加解密方法替代。

总结:
通过定制IGetAccessorFactory/ISetAccessorFactory接口,我们很容易就切入到对象持久化的流程中,
本文只是给出了一个数据加密的例子,相信大家能找到更多可应用的场合。

对于本文案例,还有一个缺点,就是再对数据进行加解密时,必须保证它的类型不变,
这就限制我们只能对字符串进行加解密,当然如果能将int加密后还是int,那也是能用的。

另一个问题就是数据加密后,显然就没法查找了,这只能通过其它方式来弥补了,如使用Lucene.

<script type="text/javascript" src="http://www.cchensoft.com/gad/blog_csdn_article.js"></script>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值