0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Go言語】WebフレームワークBeegoでユーザ情報をハッシュ化して登録する方法

Posted at

サンプル

画面でユーザ情報を入力して送信ボタンをクリックします。

Beego登録.png

データベースに登録されるとEmailをキーにして単一のユーザ情報を画面側に返却します。

Beego登録デバッグ.png

PostgreSQLを確認するとちゃんと登録されています。

Beego登録PostgreSQL.png

このような画面を作っていきます。

この記事で会う使う技術

技術 パッケージ等
トランザクション
ORMマッパー
パスワードハッシュ化 golang.org/x/crypto/bcrypt

パスワードハッシュ化に関するパッケージはこちら↓

Beegoのバージョン

Beego バージョン
Beego 2.0

ディレクトリ構造

パスワードをハッシュ化するクラスcrypt.goを追加しました。
そのほかに、todo.goクラスやdefault.goクラスも変更しました。

詳しくは後述します。

My-First-Beego-Project
├─ conf
│  └─ app.conf
├─ controllers
│  └─ default.go
├─ crypto
│  └─ crypt.go
├─ models
│  └─ todo.go
└─ routers
   └─ router.go
static
├─ css
├─ img
├─ js
│  ├─ form.js
│  └─ reload.min.js
├─ lib
│  └─ boostrap
│     ├─ css
│     │  ├─ bootstrap-grid.min.css
│     │  └─ bootstrap.min.css
│     └─ js
│        ├─ bootstrap-bundle.min.js
│        └─ bootstrap.min.js
├─ jquery
│     └─ jquery.js
├─ views
│  ├─ index.tpl
│  ├─ subIndex.tpl
│  └─ thirdIndex.tpl
└─ main.go

フロント側の画面

こちらは特に変えていませんが、載せておきます。

views/thirdIndex.tpl
<!DOCTYPE>
<html>
    <head>
        <title>3つめのページ</title>
        <!--共通ファイル-->
        <link rel="stylesheet" type="text/css" href="/static/lib/bootstrap/css/bootstrap.min.css"/>
        <script type="text/javascript" src="/static/lib/jquery/jquery.js"></script>
        <script type="text/javascript" src="/static/js/form.js"></script>
    </head>
    <body>
        <h2>取得したURLクエリパラメータは:{{.ID}}</h2>
        <form>
            <div class="form-group">
                <label>名前</label>
                <input type="text" id="name" name="name" class="form-control border border-dark" required/>
            </div>
            <div class="form-group">
                <label>E-mail</label>
                <input type="email" id="email" name="email" class="form-control border border-dark" required/>
            </div>
            <div class="form-group">
                <label>パスワード</label>
                <input type="password" id="password" name="password" class="form-control border border-dark" required/>
            </div>
            <div class="mt-4">
                <button type="button" id="submitBtn" class="btn btn-primary">
                    送信
                </button>
            </div>
        </form>

        <div>
        送信したデータ
        <div id="requestedName"></div>
        <div id="requestedEmail"></div>
        <div id="requestedPassword"></div>
        </div>
    </body>
</html>

サーバ側の画面

パスワードをハッシュするためのパッケージgolang.org/x/crypto/bcryptをインストールしておきます。

go get golang.org/x/crypto/bcrypt

インストールしたら、crypt.goクラスを作成しておきます。

crypt/crypt.go
package crypto

import (
	"golang.org/x/crypto/bcrypt"
)

// パスワードのハッシュ化処理
func GeneratedPasswordHashed(password string) (string, error) {
	hash, error := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	return string(hash), error
}

// 入力されたパスワードとデータベースのパスワードの比較
func ComparedHashedPassword(hasedPassword, password string) error {
	return bcrypt.CompareHashAndPassword([]byte(hasedPassword), []byte(password))
}

次にモデルクラスです。

models/todo.go
package models // ここでパッケージ名を指定

import (
	"time"

	"github.com/beego/beego/v2/client/orm"
	_ "github.com/lib/pq" // PostgreSQL ドライバをインポート
)

type Register struct {
	Id        int64     `orm:"auto"`
	Name      string    `orm:"size(20)"`
	Email     string    `orm:"size(50)"`
	Password  string    `orm:"size(100)"`
	CreatedAt time.Time `orm:"auto_now;type(datetime)"`
}

func init() {
	// PostgreSQLのドライバ登録
	orm.RegisterDriver("postgres", orm.DRPostgres)

	// データベース接続設定
	orm.RegisterDataBase("default", "postgres", "user=postgres password=postgres host=localhost port=5432 dbname=beegoDb sslmode=disable")

	// モデルの登録
	orm.RegisterModel(new(Register)) // Todo

	// テーブルが存在しない場合に作成(強制的にマイグレーション)
	orm.RunSyncdb("default", false, true)
}

さいごに、default.goを変更します。

controllers/default.go
package controllers

import (
	"fmt"
	"time"

	"my-first-beego-project/models"
	_ "my-first-beego-project/models"

	"github.com/astaxie/beego"
	"github.com/beego/beego/v2/client/orm"

	"my-first-beego-project/crypto"
)

type MainController struct {
	beego.Controller
}

func (c *MainController) Get() {
	c.Data["Website"] = "beego.me"
	c.Data["Email"] = "astaxie@gmail.com"
	c.TplName = "index.tpl"
}

// 20250205追加
type SubController struct {
	beego.Controller
}

type ThirdController struct {
	beego.Controller
}

type UserController struct {
	beego.Controller
}

// 20250205
func (c *SubController) Get() {
	c.Data["Page"] = "SubPage"
	c.TplName = "subIndex.tpl"
}

// @router :id[get]
func (this *ThirdController) Get() {
	this.Data["ID"] = this.Ctx.Input.Param(":id")
	this.TplName = "thirdIndex.tpl"
}

func (c *UserController) Post() {
	//フォームデータを取得する
	name := c.GetString("name")
	email := c.GetString("email")
	password := c.GetString("password")

	//デバッグ用
	//fmt.Println("フォーム画面から取得したNameは:", name)
	//fmt.Println("フォーム画面から取得したEmailは:", email)
	//fmt.Println("フォーム画面から取得したPasswordは:", password)

	c.Data["json"] = map[string]interface{}{
		"status":  "成功",
		"message": "フォーム画面からデータを受け取りました。",
		"requestData": map[string]string{
			"Name":     name,
			"Email":    email,
			"Password": password,
		},
	}
	/*
		c.Data["json"] = map[string]string{
			"status":"成功",
			"message":"フォーム画面からデータを受け取りました。",
		}
	*/
	//パスワードのハッシュ化
	generatedHashedPassword, error := crypto.GeneratedPasswordHashed(password)

	if error != nil {
		fmt.Println("パスワードを暗号化中にエラーが発生しました。", error)
		c.Data["json"] = map[string]string{
			"status":  "失敗",
			"message": "パスワードのハッシュ化に失敗しました。",
		}
		c.ServeJSON()
		return
	}
	//ORMを取得する
	o := orm.NewOrm()
	//モデルTodoのインスタンスを生成
	var registerUser models.Register //var todo models.Todo
	//トランザクション開始
	tx, err := o.Begin()

	if err != nil {
		fmt.Println("トランザクション開始エラー", err)
		c.Data["json"] = map[string]string{
			"status":  "失敗",
			"message": "トランザクションの開始に失敗しました。",
		}
	}

	registerUser.Name = name
	registerUser.Email = email
	registerUser.Password = generatedHashedPassword
	registerUser.CreatedAt = time.Now()

	_, err = tx.Insert(&registerUser)
	if err != nil {
		tx.Rollback()
		fmt.Println("エラー発生", err)
		c.Data["json"] = map[string]string{
			"status":  "失敗",
			"message": "ユーザ登録に失敗しました。",
		}
		c.ServeJSON()
		return
	}
	//成功した場合コミット
	err = tx.Commit()

	if err != nil {
		fmt.Println("トランザクションのコミットに失敗しました。", err)
		c.Data["json"] = map[string]string{
			"status":  "失敗",
			"message": "トランザクションのコミットに失敗しました。",
		}
		c.ServeJSON()
		return
	}

	//登録したデータを取得する
	var registeredUser models.Register
	err = o.QueryTable("register").Filter("Email", email).One(&registeredUser)

	if err != nil {
		fmt.Println("ユーザ情報の取得に失敗しました。", err)
		c.Data["json"] = map[string]string{
			"status":  "失敗",
			"message": "ユーザー情報の取得に失敗しました。",
		}
		c.ServeJSON()
		return
	}

	fmt.Println("登録されたユーザは、", registeredUser.Name)
	fmt.Println("登録されたEmailは、", registeredUser.Email)

	//成功時のレスポンス
	c.Data["json"] = map[string]interface{}{
		"status":  "成功",
		"message": "ユーザーが正常に登録されました",
		"requestData": map[string]string{
			"Name":  registeredUser.Name,
			"Email": registeredUser.Email,
		},
	}

	//JSONデータを返却する
	c.ServeJSON()
}

Beego ver2.0でのトランザクションの方法

Beego ver 2.0でトランザクションをする方法は下記の手順になります。

o := orm.NewOrm()でOrmオブジェクトを作成する

sample.go
o := orm.NewOrm()

tx,err := o.Begin()でトランザクションを開始する

Beego v2のORM(beego/v2)では、トランザクション管理は少し異なり、o.Begin()を使う代わりにo.Begin()で返されたtx(トランザクション)を使います。
txを使ってInsert、Commit、Rollbackなどの操作を行います。

sample.go
tx, err := o.Begin()

DBに挿入したいModelインスタンスを作成する

sample.go
var registerUser models.Register

データ更新が失敗した場合ロールバックを行う

sample.go
	_, err = tx.Insert(&registerUser)
	if err != nil {
		tx.Rollback()
		fmt.Println("エラー発生", err)
		c.Data["json"] = map[string]string{
			"status":  "失敗",
			"message": "ユーザ登録に失敗しました。",
		}
		c.ServeJSON()
		return
	}

データ更新成功後はコミットする

sample.go
err = tx.Commit()

登録したユーザ情報を画面側に渡す方法

o.QueryTable("モデル名").Filter("カラム名", カラム値).One(&モデルポインタ)を使ってデータを取得します。

o.QueryTable("モデル名").Filter("カラム名", カラム値).One(&モデルポインタ) の引数として ポインタ型で渡します。

そのため、今回はOne() メソッドは、データを構造体にマッピングするためにポインタを必要とします。

ですので、&registeredUser とする必要があります。

変数errがQueryTableの実行結果でエラーが発生した場合、err != nilが評価され、そのエラーメッセージが表示されます。

sample.go
//登録したデータを取得する
var registeredUser models.Register
err = o.QueryTable("register").Filter("Email", email).One(&registeredUser)

この場合は、emailをキーにしてデータベースから登録したユーザーの情報を取得します。

参考にしたサイト

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?