A user service, because what is a shop without users to buy our awesome red pants?
The User service is part of the ACME Fitness Shop. The goal of this specific service is to register and authenticate users using JWT tokens.
There are different dependencies based on whether you want to run a built container, or build a new one.
Use this command to pull the latest tagged version of the shipping service:
docker pull gcr.io/vmwarecloudadvocacy/acmeshop-user:stable
To build a docker container, run docker build . -t vmwarecloudadvocacy/acmeshop-user:<tag>
.
The images are tagged with:
<Major>.<Minor>.<Bug>
, for example1.1.0
stable
: denotes the currently recommended image appropriate for most situationslatest
: denotes the most recently pushed image. It may not be appropriate for all use cases
To build the app as a stand-alone executable, run go build
from the cmd/users
directory.
The user service, either running inside a Docker container or as a stand-alone app, relies on the below environment variables:
- USERS_HOST: The IP of the user app to listen on (like
0.0.0.0
) - USERS_PORT: The port number for the user service to listen on (like
8083
) - USERS_DB_USERNAME: The username to connect to the MongoDB database
- USERS_DB_PASSWORD: The password to connect to the MongoDB database
- USERS_DB_HOST: The host or IP on which MongoDB is active
- USERS_DB_PORT: The port on which MongoDB is active
- REDIS_HOST: The host or IP on which RedisDB is active
- REDIS_PORT: The port on which RedisDB is active
- REDIS_PASSWORD: The password for RedisDB. This field must be provided else the value defaults to secret
- JAEGER_AGENT_HOST: The host for Jaeger agent - Use this only if you want tracing enabled
- JAEGER_AGENT_PORT: The port for Jaeger agent - Use this only if you want tracing enabled
The Docker image is based on the Bitnami MiniDeb container. Use this commands to run the latest stable version of the payment service with all available parameters:
# Run the MongoDB container
docker run -d -p 27017:27017 --name mgo -e MONGO_INITDB_ROOT_USERNAME=mongoadmin -e MONGO_INITDB_ROOT_PASSWORD=secret -e MONGO_INITDB_DATABASE=acmefit gcr.io/vmwarecloudadvocacy/acmeshop-user-db:latest
# Run the Redis container
docker run -d -p 6379:6379 -e REDIS_PASSWORD=secret --name redis bitnami/redis
# Run the user service
docker run -d -e USERS_HOST=0.0.0.0 -e USERS_PORT=8081 -e USERS_DB_USERNAME=mongoadmin -e USERS_DB_PASSWORD=secret -e USERS_DB_HOST=0.0.0.0 -e REDIS_HOST=0.0.0.0 -e REDIS_PORT=6379 -e REDIS_PASSWORD=secret -e JAEGER_AGENT_HOST=localhost -e JAEGER_AGENT_PORT=6831 -p 8083:8083 gcr.io/vmwarecloudadvocacy/acmeshop-user:stable
There are four pre-created users loaded into the database:
User | Password |
---|---|
eric | vmware1! |
dwight | vmware1! |
han | vmware1! |
phoebe | vmware1! |
Returns the list of all users
curl --request GET \
--url http://localhost:8083/users \
-H 'Authorization: Bearer <TOKEN>'
{
"data": [
{
"username": "walter",
"email": "walter@acmefitness.com",
"firstname": "Walter",
"lastname": "White",
"id": "5c61ed848d891bd9e8016898"
},
{
"username": "dwight",
"email": "dwight@acmefitness.com",
"firstname": "Dwight",
"lastname": "Schrute",
"id": "5c61ed848d891bd9e8016899"
}
]}
Returns details about a specific user id
curl --request GET \
--url http://localhost:8083/users/5c61ed848d891bd9e8016899 \
-H 'Authorization: Bearer <TOKEN>'
{
"data": {
"username": "dwight",
"email": "dwight@acmefitness.com",
"firstname": "Dwight",
"lastname": "Schrute",
"id": "5c61ed848d891bd9e8016899"
},
"status": 200
}
Authenticate and Login user
curl --request POST \
--url http://localhost:8083/login \
--header 'content-type: application/json' \
--data '{
"username": "username",
"password": "password"
}'
The request to login needs to have a username and password
{
"username": "username",
"password": "password"
}
When the login succeeds, an access token is returned
{
"access_token": "eyJhbGciOiJIUzI1NiIsImtpZCI6InNpZ25pbl8xIiwidHlwIjoiSldUIn0.eyJVc2VybmFtZSI6ImVyaWMiLCJleHAiOjE1NzA3NjI5NzksInN1YiI6IjVkOTNlMTFjNmY4Zjk4YzlmYjI0ZGU0NiJ9.n70EAaiY6rbH1QzpoUJhx3hER4odW8FuN2wYG1sgH7g",
"refresh_token": "eyJhbGciOiJIUzI1NiIsImtpZCI6InNpZ25pbl8yIiwidHlwIjoiSldUIn0.eyJleHAiOjE1NzA3NjM1NzksInN1YiI6IjVkOTNlMTFjNmY4Zjk4YzlmYjI0ZGU0NiJ9.zwGB1340IVMLjMf_UnFC_rEeNdD131OGPcg_S0ea8DE",
"status": 200
}
The access_token is used to make requests to other services to get data. The refresh_token is used to request new access_token. If both refresh_token and access_token expire, then the user needs to log back in again.
Request new access_token by using the refresh_token
curl --request POST \
--url http://localhost:8083/refresh-token \
--header 'content-type: application/json' \
--data '{
"refresh_token" : "eyJhbGciOiJIUzI1NiIsImtpZCI6InNpZ25pbl8yIiwidHlwIjoiSldUIn0.eyJleHAiOjE1NzA3NjM1NzksInN1YiI6IjVkOTNlMTFjNmY4Zjk4YzlmYjI0ZGU0NiJ9.zwGB1340IVMLjMf_UnFC_rEeNdD131OGPcg_S0ea8DE"
}'
The request to the refresh-token service, needs a valid refresh_token
{
"refresh_token" : "eyJhbGciOiJIUzI1NiIsImtpZCI6InNpZ25pbl8yIiwidHlwIjoiSldUIn0.eyJleHAiOjE1NzA3NjM1NzksInN1YiI6IjVkOTNlMTFjNmY4Zjk4YzlmYjI0ZGU0NiJ9.zwGB1340IVMLjMf_UnFC_rEeNdD131OGPcg_S0ea8DE"
}
When the token is valid, a new access_token is returned
{
"access_token": "eyJhbGciOiJIUzI1NiIsImtpZCI6InNpZ25pbl8xIiwidHlwIjoiSldUIn0.eyJVc2VybmFtZSI6ImVyaWMiLCJleHAiOjE1NzA3NjMyMjksInN1YiI6IjVkOTNlMTFjNmY4Zjk4YzlmYjI0ZGU0NiJ9.wrWsDNor28aWv6huKUHAuVyROGAXqjO5luPfa5K5NQI",
"refresh_token": "eyJhbGciOiJIUzI1NiIsImtpZCI6InNpZ25pbl8yIiwidHlwIjoiSldUIn0.eyJleHAiOjE1NzA3NjM1NzksInN1YiI6IjVkOTNlMTFjNmY4Zjk4YzlmYjI0ZGU0NiJ9.zwGB1340IVMLjMf_UnFC_rEeNdD131OGPcg_S0ea8DE",
"status": 200
}
Verify access_token
curl --request POST \
--url http://localhost:8083/verify-token \
--header 'content-type: application/json' \
--data '{
"access_token": "eyJhbGciOiJIUzI1NiIsImtpZCI6InNpZ25pbl8xIiwidHlwIjoiSldUIn0.eyJVc2VybmFtZSI6ImVyaWMiLCJleHAiOjE1NzA3NjMyMjksInN1YiI6IjVkOTNlMTFjNmY4Zjk4YzlmYjI0ZGU0NiJ9.wrWsDNor28aWv6huKUHAuVyROGAXqjO5luPfa5K5NQI"
}'
The request to verify-token needs a valid access_token
{
"access_token": "eyJhbGciOiJIUzI1NiIsImtpZCI6InNpZ25pbl8xIiwidHlwIjoiSldUIn0.eyJVc2VybmFtZSI6ImVyaWMiLCJleHAiOjE1NzA3NjMyMjksInN1YiI6IjVkOTNlMTFjNmY4Zjk4YzlmYjI0ZGU0NiJ9.wrWsDNor28aWv6huKUHAuVyROGAXqjO5luPfa5K5NQI"
}
If the the JWT is valid and user is authorized, an HTTP/200 message is returned
{
"message": "Token Valid. User Authorized",
"status": 200
}
If the JWT is not valid (either expired or invalid signature) then the user is NOT authorized and an HTTP/401 message is returned
{
"message": "Invalid Key. User Not Authorized",
"status": 401
}
Logout the user - Adds the access token to redis cache
curl -X POST \
http://localhost:8083/logout \
-H 'Authorization: Bearer <TOKEN>'
Register/Create new user
curl --request POST \
--url http://localhost:8083/register \
--header 'content-type: application/json' \
--data '{
"username":"peterp",
"password":"vmware1!",
"firstname":"amazing",
"lastname":"spiderman",
"email":"peterp@acmefitness.com"
}'
To create a new user, a valid user object needs to be provided
{
"username":"peterp",
"password":"vmware1!",
"firstname":"amazing",
"lastname":"spiderman",
"email":"peterp@acmefitness.com"
}
When the user is successfully created, an HTTP/201 message is returned
{
"message": "User created successfully!",
"resourceId": "5c61ef891d41c8de20281dd2",
"status": 201
}
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
Please make sure to update tests as appropriate.
See the LICENSE file in the repository