flask_peeweeのRestAPIで他ユーザーのデータの更新を制限する

flask_peeweeのRestAPIには他ユーザーのデータ更新を制限する機能が実装されているので
試してみたいと思います。


先日、RestAPIで返却するパラメータを制限するのにRestResourceというクラスのサブクラスを作成しました

from flaskext.rest import RestResource

class UserResource(RestResource):
    exclude = ('password')

似たような感じでRestrictOwnerResourceというクラスを使用することによって、その名の通りの機能を
導入することができます。
RestrictOwnerResourceはRestResourceのサブクラスです。

from flaskext.rest import RestrictOwnerResource

class PostResource(RestrictOwnerResource):
    owner_field = 'user'

api.register(Post, PostResource)

user情報を保存するフィールド名をowner_fieldに文字列でもたせておきます。

あらかじめadminとadmin2という2つのユーザーを用意して試してみます。

import requests

# apiからadminユーザーとしてpostで登録
res = requests.post('http://localhost:5000/api/post/', data={"data": '{"title": "test", "entry": "test_entry"}'}, auth=("admin","admin"))
res
# =><Response [200]>
res.content
# => '{\n  "entry": "test_entry",\n  "created": "2011-11-15 17:24:30",\n  "user_id": 1,\n  "id": 1,\n  "title": "test"\n}'

# apiからadmin2ユーザーとしてdeleteを試みる
res = requests.delete('http://localhost:5000/api/post/1/', auth=("admin2","admin2"))
res
# => <Response [403]>
res.content
# => u'Forbidden'

# apiからadminユーザーとしてdeleteを試みる
res = requests.delete('http://localhost:5000/api/post/1/', auth=("admin","admin"))
res
# => <Response [200]>
res.content
# => '{\n  "deleted": 1\n}'


登録したユーザーと別のユーザーで削除しようとすると403エラーが返されることがわかります。



全体のソース

import datetime
from flask import Flask, render_template
from flaskext.auth import Auth, BaseUser
from flaskext.admin import Admin, ModelAdmin
from flaskext.db import Database
from flaskext.rest import RestAPI, UserAuthentication, RestResource,\
     RestrictOwnerResource
from peewee import TextField, DateTimeField, CharField, ForeignKeyField,\
     BooleanField

# configure our database
DATABASE = {
    'name': 'flask_peewee_sample.db',
    'engine': 'peewee.SqliteDatabase',
}
DEBUG = True
SECRET_KEY = '***********************'

app = Flask(__name__)
app.config.from_object(__name__)

db = Database(app)


# model
class User(db.Model, BaseUser):
    username = CharField()
    password = CharField()
    email = CharField()
    active = BooleanField(default=True)
    admin = BooleanField(default=False)
    created = DateTimeField(default=datetime.datetime.now)

    def __unicode__(self):
        return self.username


class Post(db.Model):
    user = ForeignKeyField(User)
    title = CharField()
    entry = TextField()
    created = DateTimeField(default=datetime.datetime.now)


class PostAdmin(ModelAdmin):
    columns = ('title', 'entry', 'created',)


class UserResource(RestResource):
    exclude = ('password')


class PostResource(RestrictOwnerResource):
    owner_field = 'user'


# for admin site
auth = Auth(app, db, user_model=User)
admin = Admin(app, auth)
auth.register_admin(admin)
admin.register(Post, PostAdmin)
admin.setup()

# for restapi
user_auth = UserAuthentication(auth)
api = RestAPI(app, default_auth=user_auth)
api.register(Post, PostResource)
api.register(User, UserResource)
api.setup()

if __name__ == '__main__':
    auth.User.create_table(fail_silently=True)
    Post.create_table(fail_silently=True)

    app.run()