
    zia                         d Z ddlmZmZmZ ddlmZ ddlmZ ddlZddl	m
Z
 ddlmZ  e
dgd	
      ZdedefdZdededefdZed   ZdedededefdZdedefdZdedefdZ G d de      ZdededefdZy)u  
資安核心:密碼雜湊 + JWT 簽發/驗證。

設計重點:
  1. 密碼用 bcrypt(慢、抗暴力破解、業界標準)
  2. JWT 含 sub(使用者 id)、type(access / refresh)、exp(到期時間)
  3. access / refresh 用同一把密鑰簽,但 type 欄位區分,避免互相混用
    )datetime	timedeltatimezone)Literal)UUIDN)CryptContext)settingsbcryptauto)schemes
deprecatedplain_passwordreturnc                 ,    t         j                  |       S )u@   把明文密碼轉成 bcrypt 雜湊字串(資料庫存這個)。)_pwd_contexthash)r   s    5/volume1/homes/robertsu/coba/app/app/core/security.pyhash_passwordr      s    ^,,    password_hashc                 .    t         j                  | |      S )u3   驗證明文密碼是否符合資料庫的雜湊。)r   verify)r   r   s     r   verify_passwordr       s    ~}==r   )accessrefreshuser_id
token_typeexpires_deltac                 2   t        j                  t        j                        }t	        |       |t        |j                               t        ||z   j                               d}t        j                  |t        j                  t        j                        S )u#   簽發 JWT 的內部共用函式。)subtypeiatexp)	algorithm)r   nowr   utcstrint	timestampjwtencoder	   JWT_SECRET_KEYJWT_ALGORITHM)r   r   r   r%   payloads        r   _create_tokenr/   +   sj    
,,x||
$C7|3==?#C-'2245	G ::gx66(BXBXYYr   c                 N    t        | dt        t        j                              S )u2   簽一個 access token(短效,用來呼叫 API)。r   )minutesr   r   )r/   r   r	   ACCESS_TOKEN_EXPIRE_MINUTESr   s    r   create_access_tokenr5   7   s#    (L(LM r   c                 N    t        | dt        t        j                              S )u?   簽一個 refresh token(長效,用來換新的 access token)。r   )daysr2   )r/   r   r	   REFRESH_TOKEN_EXPIRE_DAYSr4   s    r   create_refresh_tokenr9   @   s#    X%G%GH r   c                       e Zd ZdZy)
TokenErroru>   JWT 驗證失敗(過期、簽章錯、type 不對)時丟出。N)__name__
__module____qualname____doc__ r   r   r;   r;   I   s    Hr   r;   tokenexpected_typec                    	 t        j                  | t        j                  t        j                  g      }|j                  d      |k7  rt        d|       |j                  d      }|st        d      	 t        |      S # t         j
                  $ r}t        d      |d}~wt         j                  $ r}t        d      |d}~ww xY w# t        $ r}t        d	      |d}~ww xY w)
u  驗證並解析 JWT,回傳 user_id。

    Args:
        token         : JWT 字串
        expected_type : 期望的 token 類型("access" 或 "refresh")
                        例如保護 API 的 endpoint 只能收 access token,
                        /auth/refresh 只能收 refresh token,避免亂用。

    Raises:
        TokenError: token 過期、簽章不對、type 不符等
    )
algorithmsu   token 已過期Nu   無效的 tokenr!   u   token 類型錯誤,需要 r    u   token 缺少 sub 欄位u   token sub 不是合法 UUID)r*   decoder	   r,   r-   ExpiredSignatureErrorr;   InvalidTokenErrorgetr   
ValueError)rA   rB   r.   er    s        r   decode_tokenrK   M   s    3**UH$;$;I_I_H`a {{6m+5m_EFF
++e
C233?Cy $$ 3*+2   3*+23  ?67Q>?s;   5B 8
C C	B""C	8CC		C&C!!C&)r?   r   r   r   typingr   uuidr   r*   passlib.contextr   
app.configr	   r   r'   r   boolr   	TokenTyper/   r5   r9   	Exceptionr;   rK   r@   r   r   <module>rS      s    3 2   
 (  XJ6B-# -# -
>C > > > '(		Z4 	ZY 	Zy 	ZUX 	Z # $ 3 I I? ?I ?$ ?r   