How should I implement 'Token Based Authentication' to a set of web APIs in a secure way using PHP and MySQL (without using OAuth)?

前端 未结 2 1130
深忆病人
深忆病人 2020-12-18 08:09

I\'ve developed few web APIs in PHP using Slim framework which are used by mobile apps(iOS and Android) to process their requests and get the required data.

Eventual

相关标签:
2条回答
  • 2020-12-18 08:23

    You could do it this way.

    Each user has a private key (a random alpha-numeric x long string) - which is unique to each user.

    On every request, you can hash_hmac the request with their private key which will generate a unique request key for each user. For example:

     Request:
     GET /v1/products/coffee
    
     Private key: 
     ww9k6fcysu30sbuzu7ez57z2kzvefyxwosrjcnwo
    

    I would then generate a request key like;

    hash_hmac("sha1", "GET /v1/products/coffee", "ww9k6fcysu30sbuzu7ez57z2kzvefyxwosrjcnwo");
    

    This would give me a request key of: 45751dce6ef93655a71e7b82a6179591c346c2c1 for this GET request only. It will also ensure the client intended for this endpoint and hasn't been tampered with.

    On the receiving end you would perform the same hash_hmac routine with the users private key (they would need to pass in their username in the request - for example - to perform a lookup to fetch the private key) and compare the two results.

    hash_hmac("sha1", $_SERVER['REQUEST_METHOD'] . " " . $_SERVER['REDIRECT_URL'], $user_private_key);
    

    For added bonus, you would get a hash for POST/PUT body content and append that in the request query string and authenticate that on the receiving end. For example;

    $bodyhash = md5(implode(",", $_POST));
    

    When a user logs out, deactivate the private key and assign them a new one on next login.

    0 讨论(0)
  • 2020-12-18 08:34

    Based on our discussion, you could do something akin to OAuth2.0. I would recommend implementing the full spec, but since it is your application, you could make changes.

    Here is a graph from RFC 6750

    +--------+                               +---------------+
     |        |--(A)- Authorization Request ->|   Resource    |
     |        |                               |     Owner     |
     |        |<-(B)-- Authorization Grant ---|               |
     |        |                               +---------------+
     |        |
     |        |                               +---------------+
     |        |--(C)-- Authorization Grant -->| Authorization |
     | Client |                               |     Server    |
     |        |<-(D)----- Access Token -------|  (Slim API)   |
     |        |                               +---------------+
     |        |
     |        |                               +---------------+
     |        |--(E)----- Access Token ------>|    Resource   |
     |        |                               |     Server    |
     |        |<-(F)--- Protected Resource ---|               |
     +--------+                               +---------------+
    

    In slim, you could have as few as three endpoints:

    POST username/password:

    /oauth/v1/authenticate/

    returns { token: foo }

    GET where {token} is your unique token

    /oauth/v1/token/{token}

    returns { username: joe, permissions['page:admin','users:full'], expires: 123456}

    DELETE pass the {token}

    /oauth/v1/token/revoke

    replies with 200 OK and an empty body.

    Now, how it works:

    • When they auth, just return a JSON object with your token, which the client stores in something like a cookie.
    • The client passes this to your resource server in a header as identified in the RFC section 2.1 (which looks up the user permissions in a database/nosql/whatever):

    GET /resource HTTP/1.1

     Host: server.example.com
    
     Authorization: Bearer mF_9.B5f-4.1JqM
    

    Your resource server contacts the Slim API on the back-end to determine your permissions. The server then decides what you're allowed to see.

    If you don't like sending it as a header, see section 2.2, which describes how to send it in the body, or section 2.3 which sends it as a URI query.

    These obviously do not need to be different servers. You can implement it how you wish.

    0 讨论(0)
提交回复
热议问题