Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Building a gRPC Login Service in Go

Tech May 16 1

Development Environment

Windows 10

VS Code 1.69.2

Go 1.18.3

Project Overview

Implementation of a login service using gRPC with multiple client examples.

Data base Schema

CREATE TABLE `user_accounts` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `username` varchar(32) NOT NULL,
  `password_hash` varchar(32) NOT NULL,
  `company_id` int(10) NOT NULL,
  `created_at` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  `last_login` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  `is_deleted` tinyint(4) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `user_accounts` VALUES 
(1, 'testuser', 'e10adc3949ba59abbe56e057f20f883e', 1, '0000-00-00 00:00:00', '0000-00-00 00:00:00', 0);

Implementation Process

Project Initialization

git init
echo "# user-service" >> README.md
git add README.md
git commit -m "Initial commit"
git branch -M main
git remote add origin https://github.com/example/user-service.git
git push -u origin main

Protocol Buffer Definition

Create proto/user_auth/login.proto:

syntax = "proto3";

package auth;

option go_package = "./;auth";

message Credentials {
    string username = 1;
    string password = 2;
    string signature = 3;
}

message AuthResponse {
    string status_code = 1;
    string message = 2;
    string user_data = 3;
    string auth_token = 4;
}

service Authentication {
    rpc Authenticate(Credentials) returns (AuthResponse) {}
}

Generate gRPC code:

protoc --proto_path=./proto/user_auth/ *.proto --go-grpc_out=./proto/user_auth/
protoc --proto_path=./proto/user_auth/ *.proto --go_out=./proto/user_auth/

Server Implementation

package main

import (
    "context"
    "fmt"
    "auth"
    "net"

    "google.golang.org/grpc"
)

type AuthServer struct{}

func (s *AuthServer) Authenticate(ctx context.Context, creds *auth.Credentials) (*auth.AuthResponse, error) {
    fmt.Printf("Authentication attempt: %s\n", creds.Username)
    
    return &auth.AuthResponse{
        StatusCode: "200",
        Message:    "Authentication successful",
        UserData:   "user_profile",
        AuthToken:  "generated_token_123",
    }, nil
}

func main() {
    listener, err := net.Listen("tcp", ":8888")
    if err != nil {
        panic(err)
    }
    
    grpcServer := grpc.NewServer()
    auth.RegisterAuthenticationServer(grpcServer, &AuthServer{})
    
    fmt.Println("Server listening on :8888")
    if err := grpcServer.Serve(listener); err != nil {
        panic(err)
    }
}

Go Client Implementation

package main

import (
    "context"
    "flag"
    "fmt"
    "auth"
    "time"

    "google.golang.org/grpc"
)

var (
    serverAddr = flag.String("server", ":8888", "Server address")
    user       = flag.String("user", "testuser", "Username")
    pass       = flag.String("pass", "123456", "Password")
    sig        = flag.String("sig", "test_signature", "Request signature")
)

func authenticate(client auth.AuthenticationClient, creds *auth.Credentials) {
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()

    response, err := client.Authenticate(ctx, creds)
    if err != nil {
        fmt.Printf("Authentication error: %v\n", err)
        return
    }

    fmt.Printf("Response: %v\n", response)
}

func main() {
    flag.Parse()
    
    conn, err := grpc.Dial(*serverAddr, grpc.WithInsecure())
    if err != nil {
        fmt.Printf("Connection failed: %v\n", err)
        return
    }
    defer conn.Close()

    client := auth.NewAuthenticationClient(conn)
    authenticate(client, &auth.Credentials{
        Username:   *user,
        Password:   *pass,
        Signature: *sig,
    })
}

Configurasion Management

Create config/config.go:

package config

import (
    "github.com/tietang/props/ini"
)

func GetServerPort() string {
    config := ini.NewIniFileConfigSource("config.ini")
    return config.GetDefault("server.port", "8888")
}

func GetDatabaseDSN() string {
    config := ini.NewIniFileConfigSource("config.ini")
    user := config.GetDefault("db.user", "root")
    pass := config.GetDefault("db.password", "")
    host := config.GetDefault("db.host", "localhost")
    port := config.GetDefault("db.port", "3306")
    name := config.GetDefault("db.name", "test")
    
    return user + ":" + pass + "@tcp(" + host + ":" + port + ")/" + name + 
           "?charset=utf8mb4&parseTime=True&loc=Local"
}

Database Integration

package database

import (
    "fmt"
    "config"

    "gorm.io/driver/mysql"
    "gorm.io/gorm"
)

type UserAccount struct {
    ID           uint   `gorm:"primaryKey"`
    Username     string `gorm:"size:32"`
    PasswordHash string `gorm:"size:32"`
    CompanyID    uint
    CreatedAt    string `gorm:"type:datetime"`
    LastLogin    string `gorm:"type:datetime"`
    IsDeleted    bool
}

func Connect() (*gorm.DB, error) {
    dsn := config.GetDatabaseDSN()
    return gorm.Open(mysql.Open(dsn), &gorm.Config{})
}

func FindUser(username, passwordHash string) (*UserAccount, error) {
    db, err := Connect()
    if err != nil {
        return nil, err
    }

    var account UserAccount
    result := db.Where("username = ? AND password_hash = ?", username, passwordHash).First(&account)
    
    if result.Error != nil {
        return nil, result.Error
    }
    
    return &account, nil
}
Tags: golang

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.