gabri_1207
@gabri_1207

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

ユーザー認証時のハッシュ化したパスワードの照合について

Q&A

Closed

解決したいこと

プログラミング初心者です。
現在、WebアプリをPythonのフレームワークFastAPIで作成中です。
ログイン認証機能を作成していますが、DBのハッシュ化して格納しているパスワードとログイン時に入力したパスワードをハッシュ化して、照合し、ユーザー認証を行いたいのですが、パスワードが一致せず、困っております。
以下のように書いております。
hashlib.contextの使い方が良くないのでしょうか。
コードに不備があれば、ぜひ教えて頂きたいです。

発生している問題・エラー

出ているエラーメッセージを入力

例)

2021-03-10 06:52:25,510 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name, email, password, age, gender, height, weight, kind_of_sport, type_of_team, years_of_experience, group_id, last_login, created_at, updated_at) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
api    | 2021-03-10 06:52:25,511 INFO sqlalchemy.engine.base.Engine ('Taro', 'baseball11@gmail.com', '$2b$12$QI/qWujhn/eHbSnU2CZv0erEW8hPm.ZLshyl1ovkjVVL9Fz/qWru.', 20, '男', 165, 60, '野球', '大学硬式', 15, 0, datetime.datetime(2021, 3, 10, 6, 52, 25, 510764), datetime.datetime(2021, 3, 10, 6, 52, 25, 510793), None)
api    | 2021-03-10 06:52:25,539 INFO sqlalchemy.engine.base.Engine COMMIT
api    | 2021-03-10 06:52:25,717 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
api    | 2021-03-10 06:52:25,725 INFO sqlalchemy.engine.base.Engine SELECT `groups`.id AS groups_id, `groups`.created_at AS groups_created_at, `groups`.updated_at AS groups_updated_at, `groups`.name AS groups_name, `groups`.description AS groups_description, `groups`.capacity AS groups_capacity, `groups`.number_of_members AS groups_number_of_members
api    | FROM `groups`, users_groups 
api    | WHERE %s = users_groups.user_id AND `groups`.id = users_groups.group_id ORDER BY `groups`.id
api    | 2021-03-10 06:52:25,726 INFO sqlalchemy.engine.base.Engine (11,)
api    | 2021-03-10 06:52:25,825 INFO sqlalchemy.engine.base.Engine ROLLBACK
api    | INFO:     172.18.0.1:36596 - "POST /v0/users HTTP/1.1" 200 OK
api    | 2021-03-10 06:52:56,551 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
api    | 2021-03-10 06:52:56,567 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.email AS users_email, users.password AS users_password, users.age AS users_age, users.gender AS users_gender, users.height AS users_height, users.weight AS users_weight, users.kind_of_sport AS users_kind_of_sport, users.type_of_team AS users_type_of_team, users.years_of_experience AS users_years_of_experience, users.group_id AS users_group_id, users.last_login AS users_last_login, users.created_at AS users_created_at, users.updated_at AS users_updated_at
api    | FROM users
api    | WHERE users.name = %s
api    |  LIMIT %s
api    | 2021-03-10 06:52:56,568 INFO sqlalchemy.engine.base.Engine ('Taro', 1)
api    | INFO:     172.18.0.1:36602 - "POST /v0/admin/token HTTP/1.1" 401 Unauthorized

または、問題・エラーが起きている画像をここにドラッグアンドドロップ

該当するソースコード

from typing  import Optional
from datetime import datetime, timedelta

from fastapi import APIRouter, Depends, HTTPException
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from jose import jwt
from passlib.context import CryptContext

from settings.db import session
from models.users import Users
from schemas.users import UserResponse
from schemas.admin import Tokens

router = APIRouter()

pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

OAuth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

def authenticate(name:Optional[str]=None, password:Optional[str]=None):
    """ユーザーの認証  """
    check_password=pwd_context.hash(password)
    session.commit()
    user = session.query(Users).filter(Users.name == name).first()
    if pwd_context.verify(user.password, check_password) == False:
        raise HTTPException(status_code=401, detail="パスワードが違います。")
    return user

自分で試したこと

ここに問題・エラーに対して試したことを記載してください。

0

2Answer

authenticate を下記のようにしたら、どうなりますか?

def authenticate(name:Optional[str]=None, password:Optional[str]=None):
    """ユーザーの認証  """
    session.commit()
    user = session.query(Users).filter(Users.name == name).first()
    if pwd_context.verify(password, user.password) == False:
        raise HTTPException(status_code=401, detail="パスワードが違います。")
    return user
1Like

Comments

  1. @gabri_1207

    Questioner

    回答ありがとうございます。
    解決することができました。
if pwd_context.verify(user.password, check_password) == False:

上記のコードが実行される直前で、user.password check_passwordには、どのような値が入っていますか?

0Like

Comments

  1. @gabri_1207

    Questioner

    ご質問ありがとうございます。
    ```
    2021-03-10 13:17:57,278 INFO sqlalchemy.engine.base.Engine ('Taro', 1)
    api | $2b$12$QI/qWujhn/eHbSnU2CZv0erEW8hPm.ZLshyl1ovkjVVL9Fz/qWru.
    api | $2b$12$SZg747mCOKtf1b4928Zz1OIBp5uQOZRoiU72KQyTJxWHAyoIk30dm
    api | INFO: 172.19.0.1:46922 - "POST /v0/admin/token HTTP/1.1" 401 Unauthorized
    ```
    このような値が出ました。
    パスワードが違うのか、それともハッシュ化の仕方に不備があるのでしょうか。
    記入したサンプルパスワードはどちらも「baseball11」としています
  2. 純粋にユーザー作成時のパスワードとユーザー認証時のパスワードが間違っていないか確認するために、ユーザーをパスワード「baseball11」で再登録(もしくはパスワードを「baseball11」で再設定)して確認してもらえますか?
  3. @gabri_1207

    Questioner

    ありがとうございます。
    ユーザー作成をやり直し、上記のサンプルパスワードで登録し、もう一度同じパスワードで認証を行いました。
    ```
    api | 2021-03-10 14:27:25,739 INFO sqlalchemy.engine.base.Engine ('Taro', 1)
    api | $2b$12$vnE3VwKnyJZxjN5JnPdv4OqzhAFIOyNpop/nNkntRv5k7WtbbTnfi
    api | $2b$12$1pcP2DUEeLErb27BRsmDI.rseob9pjO97FrCFbVFAw3JGvHXsS7r6
    api | INFO: 172.20.0.1:48140 - "POST /v0/admin/token HTTP/1.1" 401 Unauthorized
    ```
    そうしますと、上記の様に返ってきました。
    やはりハッシュ化の仕方がよくないのでしょうか?

    ```
    pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")


    # ユーザーアカウント
    # Objectivesテーブルとone-to-manyの関係を持つ
    class Users(Base):
    """ユーザーアカウント."""

    __tablename__ = "users"

    name = Column(String(50), nullable=False)
    email = Column(String(50), nullable=False, unique=True)
    password = Column(String(255), nullable=False)
    age = Column(Integer, nullable=False)
    gender = Column(String(3), nullable=False)
    height = Column(Integer, nullable=False)
    weight = Column(Integer, nullable=False)
    kind_of_sport = Column(String(6), nullable=False)
    type_of_team = Column(String(20), nullable=False)
    years_of_experience = Column(Integer, nullable=False)
    group_id = Column(Integer, nullable=True)
    last_login = Column(DateTime, nullable=False, default=datetime.now)
    created_at = Column(DateTime, nullable=False, default=datetime.now)
    updated_at = Column(DateTime, nullable=True, default=None)

    objectives = relationship(
    "Objectives",
    back_populates="user",
    uselist=True,
    order_by="Objectives.id",
    cascade="all, delete",
    passive_deletes=True
    )

    groups = relationship(
    "Groups",
    back_populates="users",
    uselist=True,
    order_by="Groups.id",
    secondary=users_groups
    )


    def __init__(
    self,
    name: str,
    email: str,
    password: str,
    age: int,
    gender: str,
    height: int,
    weight: int,
    kind_of_sport: str,
    type_of_team: str,
    years_of_experience: int,
    group_id:int
    ):
    """
    [params]
    str name: ユーザー名
    str email: メールアドレス
    str password: パスワード
    int age: 年齢
    str gender: 性別
    int height: 身長(cm)
    int weight: 体重(kg)
    str kind_of_sport: 種目
    str type_of_team: 年代別・競技タイプ
    int years_of_experience: 競技年数
    """
    self.name = name
    self.email = email
    self.password = pwd_context.hash(password)
    self.age = age
    self.gender = gender
    self.height = height
    self.weight = weight
    self.kind_of_sport = kind_of_sport
    self.type_of_team = type_of_team
    self.years_of_experience = years_of_experience
    self.group_id = group_id
    ```
    付け加えてですが、DBのユーザーアカウントのModelになります。

Your answer might help someone💌