go-one

module
v0.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 3, 2024 License: MIT

README

Go One

This is a modified version of go-zero. Disclamer: stability may NOT be ensured in this version.

Concept

JWT

JWT (JSON Web Token) is a compact, URL-safe means of representing claims to be transferred between two parties. The claims in a JWT are encoded as a JSON object that is used as the payload of a JSON Web Signature (JWS) structure or as the plaintext of a JSON Web Encryption (JWE) structure, enabling the claims to be digitally signed or integrity protected with a Message Authentication Code (MAC) and/or encrypted.

How JWT Works

A JWT is typically used to authenticate and authorize users. It consists of three parts:

  1. Header: Contains metadata about the token, such as the type of token (JWT) and the signing algorithm being used (e.g., HMAC SHA256 or RSA).
  2. Payload: Contains the claims. Claims are statements about an entity (typically, the user) and additional data. There are three types of
  3. claims: registered, public, and private claims. Signature: To create the signature part, you have to take the encoded header, the encoded payload, a secret, the algorithm specified in the header, and sign that.

A JWT looks like this:

xxxxx.yyyyy.zzzzz

Where xxxxx is the Base64Url encoded header, yyyyy is the Base64Url encoded payload, and zzzzz is the Base64Url encoded signature.

How to Use JWT
  1. User Login: When a user logs in with their credentials, the server verifies these credentials and if valid, the server generates a JWT and sends it back to the user.
  2. Storing the JWT: The user stores the JWT (usually in local storage or as a cookie).
  3. Making Requests: For subsequent requests, the user sends the JWT along with the request (usually in the Authorization header with the Bearer scheme).
  4. Verifying the JWT: The server receives the request, extracts the JWT from the header, verifies its signature and validity, and if the JWT is valid, processes the request.
When to Use JWT
  1. Stateless Authentication: JWTs are useful in stateless authentication scenarios, where the server does not need to keep a session state for the user.
  2. Microservices: JWTs are commonly used for authenticating requests between microservices.
  3. Mobile Applications: Because JWTs can be easily stored in a mobile device’s local storage and sent with each request, they are suitable for mobile app authentication.
  4. Single Sign-On (SSO): JWTs are often used in SSO systems because a single token can grant access to multiple applications.
  5. API Security: JWTs are a good choice for securing APIs, where clients need to authenticate themselves to access resources.
Example JWT Structure

Header


{
  "alg": "HS256",
  "typ": "JWT"
}

Payload

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true,
  "iat": 1516239022
}

Signature

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret
)

Example JWT Here's an example of a JWT:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Using JWT in a Curl Request To use a JWT in a curl request for authentication, you can include it in the Authorization header:

curl -H "Authorization: Bearer <your_jwt_token>" -X GET http://localhost:50052/v1/loans/d2cff188-4193-4b4f-8793-ae23044f40f7

Replace <your_jwt_token> with your actual JWT.

JWT provides a stateless and scalable way to handle authentication and authorization, making it a popular choice for modern web and mobile applications.

Signature
What is a Signature?

A digital signature is a cryptographic technique used to verify the authenticity and integrity of digital messages or documents. It is the digital equivalent of a handwritten signature or a stamped seal, but it offers far more inherent security.

How Signatures Work
  1. Key Pair Generation: Digital signatures rely on asymmetric cryptography, which involves generating a pair of keys: a private key (kept secret by the owner) and a public key (shared with others).
  2. Signing: To create a digital signature, a hash (a fixed-size string of characters) is generated from the message using a hash function. The private key is then used to encrypt this hash, producing the signature.
  3. Verification: To verify the signature, the recipient uses the sender's public key to decrypt the hash. The recipient also generates a hash from the received message and compares it with the decrypted hash. If the two hashes match, the signature is valid, indicating that the message has not been altered and comes from the expected sender.
When to Use Signatures
  1. Email Security: Digital signatures can be used to sign emails, ensuring that the email has not been tampered with and verifying the sender's identity.
  2. Software Distribution: When distributing software, digital signatures can be used to ensure that the software has not been altered since it was signed by the developer.
  3. Contracts and Legal Documents: Digital signatures can be used to sign contracts and other legal documents electronically.
  4. Secure Transactions: In financial transactions, digital signatures can be used to verify the authenticity of the parties involved.
Difference Between Digital Signatures and JWT

Digital Signatures

  1. Purpose: Primarily used to verify the authenticity and integrity of a message or document.
  2. Implementation: Uses asymmetric cryptography (public and private keys).
  3. Use Cases: Email security, software distribution, electronic contracts, secure transactions.
  4. Structure: Consists of the signed message/document and the digital signature.

JSON Web Tokens (JWT)

  1. Purpose: Used for stateless authentication and authorization.
  2. Implementation: Uses a combination of a secret key (symmetric) or a public/private key pair (asymmetric) to sign the token.
  3. Use Cases: Stateless authentication, single sign-on (SSO), securing APIs, mobile app authentication.
  4. Structure: Consists of three parts - header, payload, and signature. The payload contains claims (user information, roles, etc.), which can be used to authorize users.

Example of a Digital Signature Process

Signing Process

  1. Generate a hash of the message.
  2. Encrypt the hash using the sender's private key to create the digital signature.
  3. Attach the digital signature to the message.

Verification Process

  1. Decrypt the digital signature using the sender's public key to retrieve the original hash.
  2. Generate a hash of the received message.
  3. Compare the decrypted hash with the generated hash. If they match, the signature is valid.
Circuit Breaker

Circuit breakers are a critical part of building resilient systems, allowing applications to handle failures gracefully and maintain overall stability. They come in various implementations, each with distinct characteristics and use cases. Here's an explanation of the three types mentioned: circuitBreaker, dropBreaker, and nopBreaker.

circuitBreaker

A circuitBreaker is the traditional implementation of a circuit breaker pattern. It has three states: Closed, Open, and Half-Open.

  1. Closed: In this state, the circuit breaker allows all requests to pass through. If the requests succeed, the state remains closed. However, if a predefined number of failures occur, the circuit breaker transitions to the Open state.
  2. Open: When in the Open state, the circuit breaker blocks all requests, immediately returning an error or fallback response. This state helps prevent the system from being overwhelmed by continuous failures. After a specified timeout, the circuit breaker transitions to the Half-Open state.
  3. Half-Open: In this state, the circuit breaker allows a limited number of test requests to pass through. If these requests succeed, the circuit breaker transitions back to the Closed state. If they fail, the circuit breaker returns to the Open state.
dropBreaker

A dropBreaker is a simplified implementation that focuses on rate limiting by "dropping" or rejecting a certain percentage of requests based on predefined conditions. It doesn't have the traditional states of a circuit breaker but instead directly controls the flow of requests.

  1. Dropping Requests: The dropBreaker can be configured to drop a specific percentage of incoming requests, especially when the system is under heavy load or when failures are detected. This helps to protect the system from being overwhelmed.
  2. Use Cases: This approach is useful when you want to implement a simple rate-limiting mechanism or when you need to provide a basic form of load shedding without the complexity of managing state transitions.
nopBreaker

A nopBreaker stands for "No Operation Breaker" and essentially acts as a pass-through, not performing any circuit-breaking functionality.

  1. Pass-Through: All requests pass through without any interruption or checking. It does not monitor for failures or control the flow of requests.
  2. Use Cases: This implementation can be used in scenarios where circuit-breaking behavior is not needed but you want to maintain a consistent interface. It can be useful for testing, development, or in parts of the system where high availability is guaranteed and failures are rare or inconsequential. Summary
  3. circuitBreaker: Implements the full circuit breaker pattern with states (Closed, Open, Half-Open) to handle failures and protect the system.
  4. dropBreaker: Implements a simpler form of rate limiting by dropping a certain percentage of requests, providing basic load shedding. 5.nopBreaker: Does not perform any circuit-breaking functionality and allows all requests to pass through, maintaining a consistent interface for scenarios where circuit-breaking is not needed.

Choosing the right implementation depends on the specific requirements of your application and the level of resilience needed

Gunzip Middleware

Gunzip middleware is a component typically used in web servers and applications to handle incoming HTTP requests that are compressed using the gzip compression algorithm. The purpose of this middleware is to decompress the gzip-compressed request bodies so that they can be processed by the application in their original, uncompressed form.

How Gunzip Middleware Works
  1. Intercepting Requests: The middleware intercepts incoming HTTP requests before they reach the main application logic.
  2. Checking for Compression: It checks if the Content-Encoding header of the request is set to gzip, indicating that the request body is compressed.
  3. Decompressing the Body: If the request body is compressed, the middleware uses a gunzip (gzip decompression) library to decompress the body.
  4. Forwarding the Request: The decompressed request body is then forwarded to the application for processing as a regular, uncompressed request.
When to Use Gunzip Middleware
  • Handling Compressed Requests: When clients (such as web browsers or other services) send compressed data to save bandwidth.
  • API Endpoints: When building API endpoints that may receive compressed payloads from clients, especially in cases where large amounts of data are being transmitted.
  • Improving Performance: To reduce the amount of data transmitted over the network, leading to faster transfer times and lower bandwidth usage.
Example in Go (Golang)

Below is an example of how gunzip middleware might be implemented in a Go web application using the net/http package:

package main

import (
    "compress/gzip"
    "io"
    "net/http"
)

func gunzipMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        if r.Header.Get("Content-Encoding") == "gzip" {
            reader, err := gzip.NewReader(r.Body)
            if err != nil {
                http.Error(w, "Failed to decompress request body", http.StatusBadRequest)
                return
            }
            defer reader.Close()
            r.Body = io.NopCloser(reader)
        }
        next.ServeHTTP(w, r)
    })
}

func helloHandler(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("Hello, world!"))
}

func main() {
    mux := http.NewServeMux()
    mux.Handle("/", gunzipMiddleware(http.HandlerFunc(helloHandler)))

    http.ListenAndServe(":8080", mux)
}
Key Points
  • Content-Encoding: The middleware checks the Content-Encoding header to determine if the request body is gzip-compressed.
  • Decompression: It uses the gzip.NewReader to create a reader for decompressing the request body.
  • Middleware Chain: The decompressed request is passed along the middleware chain to the next handler.
Benefits of Using Gunzip Middleware
  • Transparent Decompression: Allows the application to handle compressed and uncompressed requests seamlessly.
  • Improved Efficiency: Reduces network load by allowing clients to send compressed data, which is then decompressed on the server side.
  • Better Performance: Can lead to faster request processing times by reducing the size of data transmitted over the network.

By incorporating gunzip middleware, web applications can efficiently handle compressed incoming requests, improving both performance and resource utilization.

Load Shedding in Microservices

Load shedding in microservices is a technique used to manage system resources and maintain overall stability during periods of high load or stress. It involves deliberately dropping or rejecting a portion of incoming requests when the system is experiencing high load or is at risk of being overwhelmed. This helps to ensure that the system can continue to operate effectively and provide acceptable performance for a subset of critical requests, rather than failing completely.

Key Concepts of Load Shedding
  • Graceful Degradation: Instead of the system crashing or becoming completely unresponsive under heavy load, load shedding allows the system to degrade gracefully. Non-essential or lower-priority requests are dropped to ensure that high-priority or critical services remain available.

  • Resource Protection: By shedding load, the system can protect its core resources, such as CPU, memory, and network bandwidth, from being exhausted. This helps to maintain stability and prevent cascading failures across the system.

  • Service Quality: Load shedding ensures that the quality of service for the most important or critical requests is maintained, even if it means sacrificing the quality or availability of less important services.

Techniques for Load Shedding
  • Rate Limiting: This involves setting a limit on the number of requests a service can handle within a specific time period. Once the limit is reached, additional requests are rejected or queued.

  • Prioritization: Requests can be prioritized based on their importance or urgency. Higher-priority requests are allowed through, while lower-priority ones are dropped during high load.

  • Circuit Breakers: Circuit breakers can be used to monitor the health of services and shed load by rejecting requests when a service is failing or under heavy load.

  • Bulkheads: Bulkheads isolate different parts of the system so that a failure in one part does not bring down the entire system. This can be combined with load shedding to protect critical components.

  • Queuing and Backpressure: Implementing queues can help manage load by spreading it over time. If the queue length exceeds a certain threshold, new requests can be rejected to prevent overwhelming the system.

Load Shedding Example in Microservices

Consider a microservice architecture for an e-commerce platform with various services such as product catalog, payment processing, order management, and recommendation engine. During a peak shopping event like Black Friday, the system might experience a sudden spike in traffic.

  • Critical Services: Payment processing and order management are critical services that need to be highly available to process transactions.
  • Non-Critical Services: Recommendation engine and some parts of the product catalog might be considered less critical.

Using load shedding:

  • The system can prioritize payment processing and order management, ensuring that these services remain responsive.
  • The recommendation engine might shed load by dropping requests or returning cached responses.
  • Rate limiting can be applied to the product catalog to prevent it from overwhelming the system.

By implementing load shedding, the e-commerce platform can maintain a reasonable level of service for its critical operations, even under extreme load conditions, ensuring a better user experience and system stability.

Repo Management

Useful command:
  1. push tag: git push gitlab main tag v0.0.0
  2. git checkout:
    • git checkout -b master origin/master or
    • git checkout -b main gitlab/main
  3. git push gitlab main
  4. git log gitlab/main
  5. git pull:
    • git pull gitlab main --rebase or
    • git pull gitlab main --no-rebase or
    • git pull gitlab main --ff-only
  6. git remote:
    • git remote show gitlab or
    • git remote -vv

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL