Go Backend Ecommerce: [User Login Interface] Implementation Registration - Phần 24

Nội dung bài viết

Video học lập trình mỗi ngày

Go 24 - [User Login Interface] Implementation Registration

Tiếp theo trong bài này, chúng ta sẽ triển khai quy trình người dùng đăng ký như thế nào? Quy trình đăng ký thực ra nó không hề đơn giản như những trường hợp ta nhìn thấy, là chỉ cần kiểm tra user đó có tài khoản email or mobile phone có tồn tại trong dữ liệu hay không? Mà còn có nhiều điều chúng ta cần thực hiện nó. Sau đây là quy trình nằm trong IUserLogin thuộc interface trong dự án. Phần đầy đủ và thực tế nằm đây: FULL CODE: User Registration User

Quy trình đăng ký của một user trong Shopdev (7 bước)

Bước 1: Đầu tiên qua trình đăng ký thì user sẽ kèm theo body như sau:

    VerifyKey     string `json:"verify_key"`
    VerifyType    int    `json:"verify_type"`
    VerifyPurpose string `json:"verify_purpose"`

VerifyKey chính là email or number phone mà hệ thống xác nhận cho phép đăng ký, VerifyType đây là loại gì? 1 là EMAIL, 2 là PHONE sẽ được định nghĩa thông qua internal/consts/const_code.go. Và tham số thứ 3 sẽ là VerifyPurpose chính là loại hình mục đích, nếu là test thì otp = 123456 nhằm giúp dev có thể test nhanh cùng với tester.

Tiếp theo trong video FULL CODE: User Registration User chúng ta có thể bước đầu tiền là phải mã hoá in.VerifyKey vì sao? Vì nguyên tắc bất cứ ai bất kể chính người làm ra sản phẩm cũng không thể biết được OTP này là của user nào. Ví dụ: userA@gmail.com sẽ hash ra thì trở thành 1231343476dfvsdfgsdf456 do đó sử dụng util/crypto để thực hiện điều này.

    hashKey := crypto.GetHash(strings.ToLower(in.VerifyKey))

Bước 2: Khi đã mã hoá thành hashKey tiếp theo, hãy check hashKey này đã đăng ký or đã có trong dữ liệu bảng user_base hay chưa? Nếu có return lại cho người dùng là: User đã đăng ký, vui lòng thực hiện việc quên mật khấu

    // 2. check user exists in user base
    userFound, err := s.r.CheckUserBaseExists(ctx, in.VerifyKey)
    if err != nil {
        return response.ErrCodeUserHasExists, err
    }

    if userFound > 0 {
        return response.ErrCodeUserHasExists, fmt.Errorf("user has already registered")
    }

Bước 3: Nếu user đó chưa đăng ký thì tiến hành việc send OTP thông qua 2 dịch vụ (kafka, aws email) trong video FULL CODE: User Registration User chúng ta đã biết cách thực hiện hết tất các các dịch vụ bao gồm kafka, aws smtp chúng ta sẽ nói ở bước tiếp theo, còn đây là cách tạo ra OTP

    // 3. hey userKey lưu rtrong redis, với TTL = 60s cho một token.
    // hãy cố gắng sử dụng tốc độc redis để chống SPAM OTP thông qua nhiều IPs

    userKey := utils.GetUserKey(hashKey) //fmt.Sprintf("u:%s:otp", hashKey)
    otpFound, err := global.Rdb.Get(ctx, userKey).Result()

    // util..
    switch {
    case err == redis.Nil:
        fmt.Println("Key does not exist")
    case err != nil:
        fmt.Println("Get failed::", err)
        return response.ErrInvalidOTP, err
    case otpFound != "":
        return response.ErrCodeOtpNotExists, fmt.Errorf("")
    }

Bước 4 và 5: Hãy nhớ rằng khi generator OTP hãy cố gắng set OTP đó hết hạn trong vòng 1 phút, tốt nhất hãy sử dụng hai dữ liệu đó là redismysql. Một bên sẽ check và chống spam, một bên sẽ bảo mật dữ liệu


    // 4. Generate OTP
    otpNew := random.GenerateSixDigitOtp()
    if in.VerifyPurpose == "TEST_USER" {
        otpNew = 123456
    }
    fmt.Printf("Otp is :::%d\n", otpNew)
    // 5. save OTP in Redis with expiration time
    err = global.Rdb.SetEx(ctx, userKey, strconv.Itoa(otpNew), time.Duration(consts.TIME_OTP_REGISTER)*time.Minute).Err()

    if err != nil {
        return response.ErrInvalidOTP, err
    }

Bước 6: Sử dụng kafka or email SMTP được xây dựng từ amazon service để làm điều đó dưới đây:

Code như sau:

    // send email OTP by JAVA
    // 6/ Sen OTP
    switch in.VerifyType {
    case consts.EMAIL:
        err = sendto.SendTextEmailOtp([]string{in.VerifyKey}, consts.HOST_EMAIL, strconv.Itoa(otpNew))
        if err != nil {
            return response.ErrSendEmailOtp, err
        }
        // 7. save OTP to MYSQL
        result, err := s.r.InsertOTPVerify(ctx, database.InsertOTPVerifyParams{
            VerifyOtp:     strconv.Itoa(otpNew),
            VerifyType:    sql.NullInt32{Int32: 1, Valid: true},
            VerifyKey:     in.VerifyKey,
            VerifyKeyHash: hashKey,
        })

        if err != nil {
            return response.ErrSendEmailOtp, err
        }

        // 8. getlasId
        lastIdVerifyUser, err := result.LastInsertId()
        if err != nil {
            return response.ErrSendEmailOtp, err
        }
        log.Println("lastIdVerifyUser", lastIdVerifyUser)
        return response.ErrCodeSuccess, nil
    case consts.MOBILE:
        return response.ErrCodeSuccess, nil
    }

    // send OTP via Kafak JAVA
    body := make(map[string]interface{})
    body["otp"] = otp
    body["email"] = email

    bodyRequest, _ := json.Marshal(body)

    message := kafka.Message{
        Key:   []byte("otp-auth"),
        Value: []byte(bodyRequest),
        Time:  time.Now(),
    }

    err = global.KafkaProducer.WriteMessages(context.Background(), message)
    if err != nil {
        fmt.Printf("err send to kafka::%v\n", err)
        return response.ErrSendEmailOtp
    }

Bước 7: hãy lưu ý code phía trên, chúng ta nhận ra rằng khi OTP đã được send thì hãy ghi dữ liệu lại ở một table user_verify nhắm thao tác trích xuất xem user này đã sử dụng hay chưa...

    // 7. save OTP to MYSQL
    result, err := s.r.InsertOTPVerify(ctx, database.InsertOTPVerifyParams{
        VerifyOtp:     strconv.Itoa(otpNew),
        VerifyType:    sql.NullInt32{Int32: 1, Valid: true},
        VerifyKey:     in.VerifyKey,
        VerifyKeyHash: hashKey,
    })

Quy trình đăng ký user nó không phức tạp đúng không?

Source Code FULL

Bạn có thể get các thông tin ở đây:

FULL CODE: User Registration User

Có thể bạn đã bị missing