首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Django API实现

Django API实现
EN

Code Review用户
提问于 2014-03-13 10:11:53
回答 2查看 474关注 0票数 8

我正在构建一个移动应用程序的后端,该应用程序将托管在连接到PostgreSQL数据库的Django站点上。

我从来没有建立任何东西来完成这一点,这是我的第一次尝试。我以前没有研究过这种类型的应用程序,所以请告诉我,下面的代码是否遵循这个任务的最佳实践,是否安全,并且没有任何明显的问题。如果有一个行业标准,这是非常不同的,请让我知道它是什么,为什么它是首选。

我的客户通过视图readJSON连接:

代码语言:javascript
复制
@csrf_exempt
def readJSON(request):
    if request.method == 'POST':
        try:
            c = connections['postgres_db'].cursor()
            json_data = json.loads(request.body)
            if json_data['tag'] == 'register':
                return HttpResponse(cc().register(c, json_data))
            elif json_data['tag'] == 'syncprofile':
                return HttpResponse(cc().syncProfile(c, json_data))
################ A long list of other possible tags
            else:
                raise Http404
        finally:
            c.close()
    else:
        raise Http404

我有一个单独的类,它保存所有处理传入JSON请求的代码。这就是其中一个功能。

代码语言:javascript
复制
    def register(self, c, json_data):
    import bcrypt as bc
    salt = bc.gensalt()
    pwrd = json_data['data']['password']
    hash = bc.hashpw(pwrd, salt)
    try:
        c.execute("INSERT INTO profiles VALUES (DEFAULT, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)",
            (json_data['data']['email'], hash, salt, json_data['data']['date_created'],
            json_data['data']['state_lvl'], True,
            json_data['data']['first_name'], json_data['data']['last_name'],
            json_data['data']['sex'], json_data['data']['age'],
            json_data['data']['state'], json_data['data']['country'],
            json_data['data']['language'], json_data['data']['device_type'],
            json_data['data']['device'], json_data['data']['device_width'],
            json_data['data']['device_height'], json_data['data']['device_screen_density']
        ))
        json_response = json.dumps({"success": 1, "errors": 0})
        return HttpResponse(json_response, mimetype="application/json")
    except Exception,e:
        json_response = json.dumps({"success": 0, "errors": 1, "msg": str(e)})
        return HttpResponse(json_response, mimetype="application/json")

下面是上面函数的JSON结构。

代码语言:javascript
复制
    {
   "tag":"register",
   "data":{
      "email":"email@email.com",
      "password":"app123",
      "date_created":"07/10/1967",
      "state_lvl":"1",
      "first_name":"John",
      "last_name":"Smith",
      "sex":"m",
      "age":23,
      "state":"CA",
      "country":"USA",
      "language":"english",
      "device_type":"phone",
      "device":"Nexus-5",
      "device_width":400,
      "device_height":800,
      "device_screen_density":331
   }
}
EN

回答 2

Code Review用户

发布于 2014-03-21 06:20:52

readJSON()

返回HTTP 404 ("Not“)是不正确的,除非您有意发送模糊响应作为一种由模糊的安全措施。如果您需要一个POST,而客户端只发送一个POST,那么正确的响应应该是HTTP 405 (“不允许使用方法”)。对于一个没有适当JSON标记的主体,我认为适当的响应应该是一个非特定的HTTP 400 (“不良要求”)

在if-else分支中,更愿意先使用较少的代码将分支放在首位,以避免它的发生并减少心理负担。通常,这意味着将错误处理程序放在首位。作为奖励,您可以消除一个级别的缩进。

使用一个with块作为数据库游标,而不是try-finally构造。

假设JSON标记与cc()的方法名称之间有确切的对应关系,则可以动态地分派。( syncProfile()方法与'syncprofile'不匹配,但可以相应地重命名方法。)

代码语言:javascript
复制
@csrf_exempt
def readJSON(request):
    if request.method != 'POST':
        raise Http405
    json_data = json.loads(request.body)

    # Whitelist allowable function calls for security
    if json_data['tag'] not in ['register', 'syncprofile', … ]:
        raise Http400

    cc_method = getattr(cc(), json_data['tag'])
    with connections['postgres_db'].cursor() as c:
        return HttpResponse(cc_method(c, json_data))

寄存器()

导入应该列在文件的顶部。我不会将bcrypt命名为bc,因为后者只为了保存几个字符而牺牲了清晰性。

需要插入的列很多,参数列表也很长。我认为如果您使用命名占位符,那么出错的可能性就会更小。

代码语言:javascript
复制
import bcrypt

def register(self, c, json_data):
    attr = dict(json_data['data'])
    attr['salt'] = bcrypt.gensalt()
    password = attr['password']
    attr['hash'] = bcrypt.hashpw(password, attr['salt'])
    attr['true'] = True
    try:
        c.execute("""INSERT INTO profiles VALUES (DEFAULT
                         , %(email)s
                         , %(hash)s
                         , %(salt)s
                         , %(date_created)s
                         , %(state_lvl)s
                         , %(true)s
                         , %(first_name)s
                         , %(last_name)s
                         , %(sex)s
                         , %(age)s
                         , %(state)s
                         , %(country)s
                         , %(language)s
                         , %(device_type)s
                         , %(device)s
                         , %(device_width)s
                         , %(device_height)s
                         , %(device_screen_density)s
                     )""", attr);
        json_response = json.dumps({"success": 1, "errors": 0})
    except Exception, e:
        json_response = json.dumps({"success": 0, "errors": 1, "msg": str(e)})
    return HttpResponse(json_response, mimetype="application/json")

让客户端指定概要文件创建日期有点奇怪。我只想让数据库发布一个时间戳。

我认为长参数列表表示存在问题的数据库模式。如果您想要向用户配置文件添加另一个属性,则需要进行架构更改。可能应该将profiles表拆分为包含必需项的accounts表和存储任意键值对的account_attributes表。

代码语言:javascript
复制
CREATE TABLE accounts
( id SERIAL PRIMARY KEY
, email TEXT NOT NULL
, hash TEXT NOT NULL
, salt TEXT NOT NULL
, date_created DATE NOT NULL DEFAULT statement_timestamp()
);

CREATE TABLE account_attributes
( account_id INTEGER NOT NULL
, attribute TEXT NOT NULL
, value TEXT NOT NULL
, PRIMARY KEY (account_id, attribute)
, FOREIGN KEY (account_id) REFERENCES accounts (id)
);
票数 2
EN

Code Review用户

发布于 2014-03-21 12:48:22

万一有一点帮助..。在寄存器函数中,可以简化c.execute语句字符串的创建。

代码语言:javascript
复制
execute_text = ("INSERT INTO profiles VALUES (DEFAULT, %s, %s, %s, %s, %s, %s" %
                (json_data['data']['email'], hash, salt, 
                 json_data['data']['date_created'], json_data['data']['state_lvl'], 
                 True,))
json_fields = ['first_name', 'last_name', 'sex', 'age', 'state', 'country',
               'language', 'device_type', 'device', 'device_width', 'device_height',
               'device_screen_density']

for field in json_fields:
  execute_text = "%s, %s" % (execute_text, json_data['data'][field])
execute_text = "%s)" % execute_text
票数 1
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/44244

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档