Automatic encryption and decryption when Django achieve read database

I. Introduction The
recent development of a website, using Python2.7+Django, at the time of publication of the BAE, the database appeared abnormal, because the BAEfree basic version of the database provided, you can not insert a database field contains a keyword, it came up through the use of ROT13after the algorithm to convert the contents of the field added to the way the database.

Second, the text

  1. Rot13 algorithm to achieve

    ROT13Special algorithm, encryption and decryption algorithms are the same. If you want to replace the other cryptographic algorithms, please note the distinction between encryption and decryption.

    ROT13 = string.maketrans(\
             "ABCDEFGHIJKLMabcdefghijklmNOPQRSTUVWXYZnopqrstuvwxyz",\
             "NOPQRSTUVWXYZnopqrstuvwxyzABCDEFGHIJKLMabcdefghijklm")
    
    def rot13_encode(text):
        return string.translate(text, ROT13)
    

    Click here to read the details

  2. object (new class)

    Automatic encryption and decryption functions need to have a basic understanding of the new class.
    The new class is python2.2introduced in version, all new classes all inherit from object classes.
    Why introduce the new class it? The official explanation is:

    In order to unify classes (class)and types (type).

    The contents of our relationship today is not much, if interested can ask of yourself your mother.
    We only need to know the new class has been added __getattribute__and __setattr__methods.

    Each time a new instance of the class attribute access, will be called __getattribute__method.
    And by the __setattr__way, we can achieve when the program runs by setting an example of dynamic properties of string functions, greatly facilitate our development.

    getattribute

    #coding=utf-8
    
    class A(object):    #类A继承自object,是一个新式类
        def __init__(self, id=100):
            self.id = id
    
    a = A()
    
    print a.id
    output: 100
    
    print a.__getattribute__('id')  #等价于a.id
    #output: 100
    

    We try to rewrite __getattribute__

    #coding=utf-8
    
    class A(object):    #类A继承自object,是一个新式类
        def __init__(self, id=100):
            self.id = id
    
        def __getattribute__(self, attr):
            #注意:我们使用A父类的__getattribute__方法获取属性
            #如果直接使用getattr(self, attr)获取attr属性会造成死循环
            #有兴趣可以尝试一下
            return object.__getattribute__(self, attr) + 10
    
    a = A()
    
    print a.id
    #output: 110
    
    print object.__getattribute__(a, 'id')
    #output: 100
    

    We can see that access to a property id, the call aof the __getattribute__method, the value obtained is treated, and object.__getattribute__ways to get to the real content, keep in mind that these two methods and their characteristics, while we will use ( these two methods is the core content of this article).
    setattr
    Although __getattribute__the protagonist, but less __setattr__, although our function can be completed, but will be very troublesome.

    #coding=utf-8
    
    class A(object):
        def __init__(self, id = 100):
            self.id = id
    
    a = A()
    
    print a.id
    #output: 100
    
    a.__setattr__('id', 120)
    
    print a.id
    #output: 120
    

    Well, if you learn how to use __getattribute__ and __setattr__ way, that our preparatory work on the well, the following entry to the theater.
    When you insert a database field is automatically encrypted
    by the save function models.py in the model has been rewritten, we can automatically invoked when saving ROT13algorithm conversion function.
    To Articlemodel as an example:

    #coding=utf-8
    from django.db import models
    
    #实现ROT13算法
    #当然,真正开发时该算法肯定不会写在models.py里
    #这里为了简化代码,直接写在了这里
    ROT13 = string.maketrans(\
             "ABCDEFGHIJKLMabcdefghijklmNOPQRSTUVWXYZnopqrstuvwxyz",\
             "NOPQRSTUVWXYZnopqrstuvwxyzABCDEFGHIJKLMabcdefghijklm")
    def rot13_encode(text):
        return string.translate(text, ROT13)
    
    
    class Article(models.Model, object):
        #以下为最初的字段(仅挑选出了相关字段)
        title = models.CharField(max_length=200)
        content = models.TextField()
        hot = models.IntegerField(default=0) #文章的热度,此字段无需加密
    
        #使用以下字段记录相关字段是否是加密状态
        #使用"{name}_en"的方式命名,便于操作
        title_en = models.BooleanField(default=False)
        content_en = models.BooleanField(default=False)
    
        #encrypt_items记录哪些字段需要加密
        encrypt_items = ['content', 'title']
    
        #重写Model的save函数,实现当向数据库插入字段时自动加密的功能
        def save(self, *args, **kwargs):
            for attr in self.encrypt_items:
                if not getattr(self, '%s_en' % attr):
                    self.__setattr__(attr, rot13_encode(getattr(self, attr)))
                    self.__setattr__('%s_en' % attr, True)
            #调用父类Model的save函数,进行真正的数据库插入操作
            super(Article, self).save(*args, **kwargs)
    

    Decrypts read from the database automatically
    override the lack of save function
    is generally used when we read the contents of the database will be written like this:

    art = Article.object.get(id=1)
    title = art.title
    content = art.content
    

    But in the previous section, rewritten savelater, when reading the contents of the database we need to write:

    art = Article.object.get(id=1)
    title = rot13_encode(art.title)
    content = rot13_encode(art.content)
    

    In this case the workload will surge to write code, and if other code has been written, it would need to change the code line by line - very painful work. So we need to Articleimprove.
    Automatically decrypted when read from the database to achieve

    #coding=utf-8
    from django.db import models
    
    #实现ROT13算法
    ROT13 = string.maketrans(\
             "ABCDEFGHIJKLMabcdefghijklmNOPQRSTUVWXYZnopqrstuvwxyz",\
             "NOPQRSTUVWXYZnopqrstuvwxyzABCDEFGHIJKLMabcdefghijklm")
    def rot13_encode(text):
        return string.translate(text, ROT13)
    
    #简化函数名称,便于调用
    OGA = object.__getattribute__
    REP = rot13_encode
    
    class Article(models.Model, object):
        title = models.CharField(max_length=200)
        content = models.TextField()
        hot = models.IntegerField(default=0) #文章的热度,此字段无需加密
    
        title_en = models.BooleanField(default=False)
        content_en = models.BooleanField(default=False)
    
        #encrypt_items记录哪些字段需要加密
        encrypt_items = ['content', 'title']
    
        def __getattribute__(self, attr):
            try:
                if (attr in OGA(self, 'encrypt_items')) and OGA(self, '%s_en' % attr):
                    #若所查询属性(字段)需要加密且已经被加密,解密后再返回
                    return REP(OGA(self, attr))
                else:
                    #所查询属性无需加密或未被加密,直接返回
                    return OGA(self, attr)
            except AttributeError as err:
                #可能出现AttributeError异常,捕获后直接上抛即可
                raise err
    
        #重写Model的save函数,实现当向数据库插入字段时自动加密的功能
        def save(self, *args, **kwargs):
            for attr in self.encrypt_items:
                if not OGA(self, '%s_en' % attr):
                    #注意:这里注释掉了进行加密的这行代码。只有这样才能正常加密!!!
                    #请往下阅读,我会说明原因
                    #self.__setattr__(attr, REP(OGA(self, attr)))
                    self.__setattr__('%s_en' % attr, True)
    
            #调用Model的save函数
            super(Article, self).save(*args, **kwargs)
    

    Some readers may wonder why that line of code to remove the real encrypt, encrypt it to function properly? (No doubt, then, this article has ended, the point of a walk praise chant ~)
    when I realized this first feature does not remove that line of code (crap!), But found that the database needs to be encrypted when I tested field is not encrypted, however title_en, and content_enthe value is 1 (on behalf of the database 1 True, 0 False).
    To debug a problem naturally, I modified a bit the last few lines of code:

    print OGA(self, 'title')
    super(Article, self).save(*args, **kwargs)
    print OGA(self, 'title')
    

    That is the call Modelof savethe former functions are print a title the true value found in the call savebefore, titleit is normally encrypted (note that I did not then comment out the line of code). But after a call to save very interesting, the real value of the title, it is a non-encrypted value.
    When the comment out after line of code, the value in the database is encrypted. In this regard, I guess (yes, guess) is calling savea function, Djangouse code similar to this:

    self.title = self.title
    

    Yes, you read right, that's it, you know, we have Articlethe __getattribute__method has been rewritten, the original title is encrypted, but once used once self.title = self.title, it will be decrypted title, this way, inserted into the database field is to be decrypted.

Author: LucianoSimon
link: https://www.jianshu.com/p/193fd76e7a96
Source: Jane book
Jane book copyright reserved by the authors, are reproduced in any form, please contact the author to obtain authorization and indicate the source.

Guess you like

Origin blog.csdn.net/qq_41433183/article/details/90733634