User Registration, Login, Session Check, and Logout API Implementation

Registration API

This API uses a singleton pattern to refactor the cloud communication SMS sending demo (please review when free).

API Documentation

URL: /avi/v1_0/users/
Method: POST
Data format: JSON
Required parameters: mobile, sms_code, password

Response format: JSON
Response parameters: errno, errmsg

Backend Logic

  1. Receive parameters
resp_dict = request.get_json()
mobile = resp_dict.get('mobile')
sms_code = resp_dict.get('sms_code')
password = resp_dict.get('password')
  1. Validate data integrity
if not all([mobile, sms_code, password]):
    resp = {
        'errno': RET.PARAMERR,
        'errmsg': 'Incomplete parameters'
    }
    return jsonify(resp)
  1. Validate mobile phone number
if not re.match(r'1[34578]\d{9}', mobile):
    resp = {
        'errno': RET.DATAERR,
        'errmsg': 'Invalid mobile number format'
    }
    return jsonify(resp)
  1. Business logic processing

    • Retrieve SMS verification code from Redis:
real_sms_code = redis_store.get('sms_code_' + mobile)
  • Check if the verification code has expired:
if real_sms_code is None:
    resp = {
        'errno': RET.NODATA,
        'errmsg': 'SMS verification code has expired'
    }
    return jsonify(resp)
  • Check if the user entered the correct verification code:
if real_sms_code != sms_code:
    resp = {
        'errno': RET.DATAERR,
        'errmsg': 'Incorrect SMS verification code'
    }
    return jsonify(resp)
  • Delete the verification code from Redis:
redis_store.delete('sms_code_' + mobile)
  • Save user data (with database rollback):
# Create user and save data
user = User(name=mobile, mobile=mobile)
# Password handling should be delegated to the model class
user.password = password

try:
    db.session.add(user)
    db.session.commit()
except Exception as e:
    # a. Log the error
    logging.error(e)
    # b. Rollback the transaction
    db.session.rollback()
    # c. Return error response
    resp = {
        'errno': RET.NODATA,
        'errmsg': 'SMS verification code has expired'
    }
    return jsonify(resp)
  • Set session information:
session['user_id'] = user.id
session['user_name'] = mobile
session['mobile'] = mobile
  1. Return success response
resp = {
    'errno': RET.OK,
    'errmsg': 'Registration successful'
}
return jsonify(resp)

User Login API

API Documentation

URL: /avi/v1_0/session/
Method: POST
Data format: JSON
Required parameters: mobile, password

Response format: JSON
Response parameters: errno, errmsg

Backend Logic Analysis

  1. Receive parameters (mobile, password).
  2. Parameter validation: overall validation, validate mobile number integrity.
  3. Get user's IP address, retrieve the number of incorrect attemtps from Redis, check if attempts exceed 5.
  4. Verify username and password match.
  5. If correct, delete the record of incorrect attempts from Redis.
  6. Set session information.
  7. Return result to frontend.

Implementation Steps

  1. Receive parameters
resp_json = request.get_json()
mobile = resp_json.get('mobile')
password = resp_json.get('password')
  1. Check parameter integrity
if not all([mobile, password]):
    return jsonify(errno=RET.PARAMERR, errmsg='Incomplete parameters')
  1. Check incorrect attempts in Redis

If the number of incorrect attempts exists and is >= 5, reject login immediately. User can try again after 10 minutes.

user_ip = request.remote_addr
access_counts = redis_store.get('access_' + user_ip)
if access_counts is not None and int(access_counts) >= 5:
    return jsonify(errno=RET.REQERR, errmsg='Maximum attempts exceeded')
  1. Query database and verify user credentials

If the user does not exist or the password does not match, increment the error count and return an error.

user = User.query.filter_by(mobile=mobile).first()
if user is None or not user.check_password(password):
    # Increment error count and set expiry
    try:
        # incr: increment error count
        redis_store.incr('access_' + user_ip)
        # expire: first argument is key, second argument is expiry time in seconds
        redis_store.expire('access_' + user_ip, 600)
    except Exception as e:
        logging.error(e)
    
    return jsonify(errno=RET.LOGINERR, errmsg='Invalid username or password')
  1. Clear incorrect attempt count on successful login
redis_store.delete('access_' + user_ip)
  1. Set session and return success
session['user_id'] = user.id
session['user_name'] = mobile
session['mobile'] = mobile

return jsonify(errno=RET.OK, errmsg='Login successful')

Check Login Status API

API Documentation

URL: /sessions
Method: GET

Response format:
{
  "data": {
    "name": "18001225173"
  },
  "errmsg": "true",
  "errno": "0"
}

Backend Logic

Attempt to retrieve the user's name from the session. If it exists, the user is logged in; otherwise, not.

name = session.get("user_name")
if name is not None:
    return jsonify(errno=RET.OK, errmsg="true", data={"name": name})
else:
    return jsonify(errno=RET.SESSIONERR, errmsg="false")

Login Required Decorator

If the user is logged in, store the user ID in the g variable. The g variable exists during the application's lifecycle.

def login_required(view_func):
    """Check user login status"""
    @wraps(view_func)
    def wrapper(*args, **kwargs):
        user_id = session.get("user_id")
        if user_id is not None:
            # User is logged in
            # Use g object to store user_id for use in view functions
            # For example, when setting avatar, session data is accessed again.
            # Using g variable avoids multiple Redis accesses.
            g.user_id = user_id
            return view_func(*args, **kwargs)
        else:
            # User not logged in
            resp = {
                "errno": RET.SESSIONERR,
                "errmsg": "User not logged in"
            }
            return jsonify(resp)
    return wrapper

Logout API

API Documentation

URL: /sessions
Method: DELETE

Backend Logic

Clear session data.

session.clear()
return jsonify(errno=RET.OK, errmsg="OK")

Tags: API Registration login Session Logout

Posted on Wed, 15 Jul 2026 17:28:18 +0000 by FormatteD_C