# Token-Based Authentication with Multiple Login Methods in Mini-Shop-Server

> Learn how mini-shop-server integrates token-based authentication with username, email, mobile, and WeChat logins. Secure your APIs with stateless signed tokens.

- Repository: [A粒麦子/mini-shop-server](https://github.com/allen7d/mini-shop-server)
- Tags: deep-dive
- Published: 2026-02-24

---

**The mini-shop-server implements a unified token-based authentication layer that supports five distinct login mechanisms—username, email, mobile, and three WeChat variants—through a centralized dispatch service that generates `itsdangerous` signed tokens for stateless API security.**

The allen7d/mini-shop-server repository demonstrates a Flask-based approach to handling diverse authentication methods under a single architecture. Rather than implementing separate authentication flows for each login type, the system uses a strategy pattern to route credentials through specialized verifiers while issuing standardized tokens for session management.

## Authentication Architecture Overview

The implementation splits responsibilities across three core components. The **API entry point** in [`app/api/v1/token.py`](https://github.com/allen7d/mini-shop-server/blob/main/app/api/v1/token.py) receives incoming credentials, the **login verification service** in [`app/service/login_verify.py`](https://github.com/allen7d/mini-shop-server/blob/main/app/service/login_verify.py) handles method-specific validation, and the **token utilities** in [`app/core/token_auth.py`](https://github.com/allen7d/mini-shop-server/blob/main/app/core/token_auth.py) manage cryptographic signing and validation.

This separation allows the system to treat a WeChat Mini-Program `code` and a traditional password with equal abstraction—both resolve to a user identity and a signed token containing the user ID, login type, and permission scope.

## Login Method Dispatch Strategy

The `LoginVerifyService.get_token` method acts as a router, mapping each `ClientTypeEnum` value defined in [`app/libs/enums.py`](https://github.com/allen7d/mini-shop-server/blob/main/app/libs/enums.py) to a specific verification handler. This dispatch pattern enables the single `/v1/token` endpoint to handle all authentication variants without conditional branching in the view layer.

### Internal Credential Methods

For traditional logins, the system supports three identifier types stored in the `Identity` model:

- **Username** (`ClientTypeEnum.USERNAME`, value `100`)
- **Email** (`ClientTypeEnum.EMAIL`, value `101`) 
- **Mobile** (`ClientTypeEnum.MOBILE`, value `102`)

Each method follows an identical verification pattern defined in [`app/service/login_verify.py`](https://github.com/allen7d/mini-shop-server/blob/main/app/service/login_verify.py). The `verify_by_username`, `verify_by_email`, and `verify_by_mobile` functions query the `Identity` table, validate the provided password against a SHA-256 hash stored in the `_credential` field, and retrieve the associated `User` record.

```python

# app/service/login_verify.py (conceptual dispatch)

promise = {
    ClientTypeEnum.USERNAME: LoginVerifyService.verify_by_username,
    ClientTypeEnum.EMAIL:    LoginVerifyService.verify_by_email,
    ClientTypeEnum.MOBILE:   LoginVerifyService.verify_by_mobile,
}
identity = promise[ClientTypeEnum(type)](account, secret)

```

### WeChat OAuth Integration

The server integrates three distinct WeChat login flows, each exchanging a temporary `code` for a persistent user identifier:

- **WeChat Mini-Program** (`ClientTypeEnum.WX_MINA`, value `200`): Uses `verify_by_wx_mina` to exchange the `code` for an OpenID via [`app/service/wx_token.py`](https://github.com/allen7d/mini-shop-server/blob/main/app/service/wx_token.py), creating or fetching the user via `UserDao.register_by_wx_mina`.
- **WeChat Open Platform** (`ClientTypeEnum.WX_OPEN`, value `202`): Handles web QR logins through `verify_by_wx_open`, calling [`app/service/open_token.py`](https://github.com/allen7d/mini-shop-server/blob/main/app/service/open_token.py) to resolve the `code` into an OpenID.
- **WeChat Official Account** (`ClientTypeEnum.WX_ACCOUNT`, value `203`): Processes H5 logins via `verify_by_wx_account`, utilizing [`app/service/account_token.py`](https://github.com/allen7d/mini-shop-server/blob/main/app/service/account_token.py) to obtain a UnionID.

All three WeChat methods bypass password hashing, storing the raw WeChat token directly in the `Identity` model while binding the user record to the WeChat identifier.

## Token Generation and Cryptography

Upon successful verification, the system generates a time-limited, signed token using `itsdangerous.URLSafeTimedSerializer` with the Flask `SECRET_KEY`. The `generate_auth_token` function in [`app/core/token_auth.py`](https://github.com/allen7d/mini-shop-server/blob/main/app/core/token_auth.py) encapsulates three critical claims:

- **`uid`**: The unique user identifier
- **`type`**: The numeric `ClientTypeEnum` value (e.g., `100` for username, `200` for WeChat Mini-Program)
- **`scope`**: The permission level (admin or common user)

```python

# app/service/login_verify.py

token = generate_auth_token(
    identity['uid'],
    type.value,
    identity['scope'],
    expiration,
)

```

This token is returned to the client and must be presented in the `Authorization` header for subsequent requests.

## Token Validation on Protected Routes

Protected endpoints utilize the `@auth.login_required` decorator from Flask-HTTPAuth. When a request arrives, the framework invokes `token_auth.verify_password` defined in [`app/core/token_auth.py`](https://github.com/allen7d/mini-shop-server/blob/main/app/core/token_auth.py), which calls `verify_auth_token` to decrypt and validate the signature.

```python

# app/core/token_auth.py

@auth.verify_password
def verify_password(token, password):
    user_info = verify_auth_token(token)
    if not user_info:
        return False
    g.user = User.get_or_404(id=user_info.uid)
    return True

```

The `decrypt_token` function verifies the cryptographic signature and expiration (defaulting to 2 hours), returning the payload tuple that populates `g.user` for the duration of the request lifecycle.

## Password Security Implementation

The `Identity` model in [`app/models/identity.py`](https://github.com/allen7d/mini-shop-server/blob/main/app/models/identity.py) implements differentiated storage strategies based on login type. For internal logins (username, email, mobile), credentials are hashed using SHA-256 before storage:

```python

# app/models/identity.py

if ClientTypeEnum(self.type) in current_app.config['CLINET_INNER_TYPES']:
    self._credential = hashlib.sha256(raw.encode('utf-8')).hexdigest()
else:
    self._credential = raw  # WeChat tokens stored as-is

```

The `check_password` method recomputes the hash for comparison, raising `AuthFailed` on mismatch to prevent timing attacks.

## Practical Implementation Examples

### Obtaining a Token via Email

```http
POST /api/v1/token HTTP/1.1
Content-Type: application/json

{
  "account": "alice@example.com",
  "secret": "securePassword123",
  "type": 101
}

```

Response:

```json
{
  "code": 200,
  "msg": "success",
  "data": {
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6..."
  }
}

```

### Accessing Protected Resources

```http
GET /api/v1/user/profile HTTP/1.1
Authorization: Basic <base64(token:)>

```

The server decodes the token, validates the signature, and loads the user into `g.user` before executing the view function.

### Server-Side Token Decryption

```python
from app.service.login_verify import LoginVerifyService

payload = LoginVerifyService.decrypt_token(token_string)
print(payload)

# Output: {'uid': 12, 'scope': 1, 'create_at': 1708739200, 'expire_in': 1708742800}

```

## Summary

- **Unified Endpoint**: The `/v1/token` route in [`app/api/v1/token.py`](https://github.com/allen7d/mini-shop-server/blob/main/app/api/v1/token.py) handles all five login variants through a single interface.
- **Strategy Pattern**: `LoginVerifyService` in [`app/service/login_verify.py`](https://github.com/allen7d/mini-shop-server/blob/main/app/service/login_verify.py) dispatches to method-specific verifiers using a `ClientTypeEnum` mapping defined in [`app/libs/enums.py`](https://github.com/allen7d/mini-shop-server/blob/main/app/libs/enums.py).
- **Cryptographic Tokens**: `itsdangerous` provides signed, tamper-proof tokens containing user ID, login type, and scope claims.
- **Stateless Validation**: The `verify_password` function in [`app/core/token_auth.py`](https://github.com/allen7d/mini-shop-server/blob/main/app/core/token_auth.py) decrypts tokens without database lookups for session state.
- **Secure Storage**: Internal passwords use SHA-256 hashing via [`app/models/identity.py`](https://github.com/allen7d/mini-shop-server/blob/main/app/models/identity.py), while WeChat credentials store raw tokens for API reconciliation.

## Frequently Asked Questions

### How does the system distinguish between different login methods?

The system uses `ClientTypeEnum` values passed in the `type` parameter (e.g., `100` for username, `101` for email, `200` for WeChat Mini-Program). The `LoginVerifyService.get_token` method maintains a dispatch dictionary mapping these integers to specific verification functions such as `verify_by_email` or `verify_by_wx_mina`, allowing a single endpoint to route requests appropriately.

### What encryption method secures the authentication tokens?

Tokens are generated using `itsdangerous.URLSafeTimedSerializer` with the Flask application's `SECRET_KEY`. This creates a cryptographically signed string that includes a timestamp, enabling the server to detect tampering and enforce expiration (default 2 hours) without maintaining server-side session storage.

### How are passwords stored for traditional login methods?

The `Identity` model in [`app/models/identity.py`](https://github.com/allen7d/mini-shop-server/blob/main/app/models/identity.py) applies SHA-256 hashing to passwords for internal login types (username, email, mobile) before storage in the `_credential` field. WeChat-based logins store the raw access token instead, as these are temporary codes exchanged for persistent identifiers through Tencent's OAuth APIs.

### Can the token payload be inspected without validation?

While the token format is URL-safe base64, the cryptographic signature prevents client-side tampering. Server-side decryption via `decrypt_token` in [`app/service/login_verify.py`](https://github.com/allen7d/mini-shop-server/blob/main/app/service/login_verify.py) or `verify_auth_token` in [`app/core/token_auth.py`](https://github.com/allen7d/mini-shop-server/blob/main/app/core/token_auth.py) validates the signature before exposing the payload containing `uid`, `type`, and `scope` claims.