59724


現在、ブログ投稿アプリケーションの実装をしているところでして、  
テンプレートにカスタムユーザのPKを直接渡してDBに登録させる仕様になっています。

◆Viewより抜粋

[code]

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['user_pk'] = self.request.user.pk
        return context
    
[/code]

◆テンプレートより抜粋

[code]

    <div class="form-group col-md-11">
        <label for="id_author">著者</label>
        <input type="hidden" name="{{ form.author.name }}" id="{{ form.author.id_for_label }}" value="{{ user_pk }}" >
    </div>
    
[/code]

そこで、hiddenでフォームは表示させておりませんが、devtoolsでは当然のことながら参照ができてしまいます。  
ですので、もし他ユーザのPKを取得された場合、投稿ユーザの改ざんが可能になってしまいます。

セキュアな部分ですので、可能ならソース側のみで完結させたいのですが、その場合どう実装したらよいでしょうか？


CC BY-SA 4.0
2019-10-05T18:21:35.293
59490
2019-10-15T11:09:19.353
2019-10-05T20:20:43.227
3060
36021
question
python django
djangoのFormで直接PKを渡してよいのか？？


pkの意味が具体的にわからないのでプライマリーキーと捉えて回答してみます。

まず、プライマリーキーについて。  
データーベースで使われる単語です。[django-
girls](https://tutorial.djangogirls.org/ja/extend_your_application/)やいくつかのブログではidという意味でpkが使われています。この意味で取るとuser_pkはuser_idと同義になります。

この場合、質問者さんの言う「他ユーザのPKを取得される」状況は十分起こりうります。その人のブログを読んだら、user_idを見ることでなりすましが可能なので、セキュリティに問題があるということになります。こうなると認証機能を実装する必要があります。

どのように認証を実装するか。  
今じゃ見ませんが、簡単なモデルとして[Basic認証](https://ja.wikipedia.org/wiki/Basic%E8%AA%8D%E8%A8%BC)が挙げられます。ユーザー名とパスワードの組み合わせを使って、その人しか知らない情報で認証します。(httpという盗聴可能な通信をするため現在では使われませんが、)ユーザー名とパスワードの組み合わせで認証するというのはどのサイトでも見ますね。

ただ毎回パスワードを入力するのも面倒であったり、のぞき見されるリスクが増えます。ですので、アクセストークンを使うやり方が考えれます。一度、パスワードで認証した人に誰にもわからない秘密鍵のようなものを渡します。以降これで認証が可能です。必要があれば、有効期限を決めて再発行したりします。(サイトによって[いろいろ違う](https://qiita.com/r7kamura/items/3e03471e02ea9ab5902a#%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%83%88%E3%83%BC%E3%82%AF%E3%83%B3%E3%81%AB%E6%9C%89%E5%8A%B9%E6%9C%9F%E9%99%90%E3%82%92%E6%8C%81%E3%81%9F%E3%81%9B%E3%81%A6%E3%81%8A%E3%81%8F%E3%81%A8%E3%81%A1%E3%82%87%E3%81%A3%E3%81%A8%E5%AE%89%E5%85%A8)みたいです)


CC BY-SA 4.0
2019-10-10T23:15:49.097
59627
2019-10-10T23:15:49.097
36129
59490
answer


自己解決しました。

フォーム定義

[code]

    class BlogForm(forms.ModelForm):
        class Meta:
            model = Blog
            # 'author'はここで処理しない
            fields = ('title', 'text', 'category')
    
[/code]

ビュー内定義

[code]

    class ScriptCreateView(generic.CreateView):
        model = Blog
        form_class = BlogForm
        template_name = 'creator/blog_create_form.html'
        success_url = reverse_lazy('Blog:home')
    
        def form_valid(self, form):
            # データベースに保存する前のモデルオブジェクトを変数に格納
            blog = form.save(commit=False)
            # ※ここでログインユーザ情報を渡す
            blog.author = self.request.user
            blog.save()
            # スーパーメソッドを呼び出しバリデーション(form.is_valid)を行う
            return super().form_valid(form)
    
[/code]

以上の処理で、投稿フォームにユーザ(PK)情報を含めずにDB登録できるようになりました。

ご回答していただいた方、ありがとうございます。


CC BY-SA 4.0
2019-10-15T11:09:19.353
59724
2019-10-15T11:09:19.353
36021
59490
answer