Materiaについては、
「Webサービスバックエンドライブラリー Materia」
を参照ください。
前提環境
> mix hex.info
Hex: 0.18.2
Elixir: 1.6.1
OTP: 20.2.4
> mix phx.new -v
Phoenix v1.3.4
プロジェクトの作成とMateriaの導入
プロジェクトを作成する
> mix phx.new materia_sample --no-brunch
> cd materia_sample
materia_sample/mix.exs
defp deps do
[
{:phoenix, "~> 1.3.2"},
{:phoenix_pubsub, "~> 1.0"},
{:phoenix_ecto, "~> 3.2"},
{:plug_cowboy, "~> 1.0"}, #<- add here
{:postgrex, ">= 0.0.0"},
{:phoenix_html, "~> 2.10"},
{:phoenix_live_reload, "~> 1.0", only: :dev},
{:gettext, "~> 0.11"},
{:cowboy, "~> 1.0"},
{:materia, "~> 0.1.0"}, #<- add here
]
end
guardian(認証ライブラリ)の設定
※必ずdeps.getの前に実施する
materia_sample/config/config.exs
# Configures Guardian
config :materia, Materia.Authenticator,
issuer: "materia_sample",
access_token_ttl: {10, :minutes}, #必須
refresh_token_ttl: {1, :days}, # refresh_tokenを定義しない場合sign-inはaccess_tokenのみ返す
user_registration_token_ttl: {35, :minutes},
password_reset_token_ttl: {35, :minutes},
secret_key: "your secusecret token",
allowed_algos: ["HS256"]
# Configures GuardianDB
config :guardian, Guardian.DB,
repo: MateriaSample.Repo, #<- mod your app repo
schema_name: "guardian_tokens", # default
#token_types: ["refresh_token"], # store all token types if not set
sweep_interval: 60 # default: 60 minutes
# Configures calender utils locale (default is server locale)
config :materia_utils, calender_locale: "Asia/Tokyo"
materia_sample/config/dev.exs
# Configure materia repo
config :materia, :repo, MateriaSample.Repo #<- add your app repo
deps.get
mix deps.get
シークレットキーの生成
> mix phx.gen.secret
hogehogehogehogheohgoehgoheohgeohgoheohgoehgoheohgeohgoehogeho
config.exsの「Configures Guardian」の末尾にシークレットキーを追加
materia_sample/config/config.exs
# Configures Guardian
config :materia, Materia.Authenticator,
issuer: "materia_sample",
…
allowed_algos: ["HS256"], # カンマを追加
# Generate mix task
# > mix phx.gen.secret
secret_key: "hogehogehogehogheohgoehgoheohgeohgoheohgoehgoheohgeohgoehogeho"
※オプション guardian sweeper(tokenの自動削除)の有効化
materia_sample/lib/materia_sample/application.ex
defmodule MateriaSample.Application do
use Application
〜中略〜
# Define workers and child supervisors to be supervised
children = [
# Start the Ecto repository
supervisor(MateriaSample.Repo, []),
# Start the endpoint when the application starts
supervisor(MateriaSampleWeb.Endpoint, []),
# Start your own worker by calling: MateriaSample.Worker.start_link(arg1, arg2, arg3)
# worker(MateriaSample.Worker, [arg1, arg2, arg3]),
worker(Guardian.DB.Token.SweeperServer, []), #<- if you wont auto sweep invalid token, you must add GuardianDB worker.
]
〜中略〜
end
seedsの設定
Materiaのテスト用seeds.exsから転記
Migrationファイルの生成&DBマイグレーション
> mix guardian.db.gen.migration
> mix materia.gen.migration
> mix ecto.create
> mix ecto.migrate
> mix run priv/repo/seeds.exs
基本的な導入作業はここまでです。
基本的なAPIを有効にして使ってみる
Materiaで用意されたルーティングを追加して起動
※ 実際のルーティング定義はサービス要件に合わせて設定する必要があります。
具体的にはユーザー情報の検索などは管理者権限の運用者のみ利用できるように設定すべきです。
materia_sample/lib/materia_sample_web/router.ex
defmodule MateriaWeb.Router do
use MateriaWeb, :router
# 今回は使わないのでコメントアウト
#pipeline :browser do
# plug :accepts, ["html"]
# plug :fetch_session
# plug :fetch_flash
# plug :protect_from_forgery
# plug :put_secure_browser_headers
#end
pipeline :guardian_auth do
plug Materia.AuthenticatePipeline
end
pipeline :tmp_user_auth do
plug Materia.UserRegistrationAuthPipeline
end
pipeline :pw_reset_auth do
plug Materia.PasswordResetAuthPipeline
end
pipeline :api do
plug :accepts, ["json"]
end
pipeline :guardian_auth do
plug Materia.AuthenticatePipeline
end
pipeline :tmp_user_auth do
plug Materia.UserRegistrationAuthPipeline
end
pipeline :pw_reset_auth do
plug Materia.PasswordResetAuthPipeline
end
scope "/api", MateriaWeb do
pipe_through :api
post "/sign-in", AuthenticatorController, :sign_in
post "/refresh", AuthenticatorController, :refresh
post "/tmp-registration", UserController, :registration_tmp_user
post "/request-password-reset", UserController, :request_password_reset
end
scope "/api", MateriaWeb do
pipe_through [ :api, :tmp_user_auth]
get "/varidation-tmp-user", AuthenticatorController, :is_varid_token
post "/user-registration", UserController, :registration_user
post "/user-registration-and-sign-in", UserController, :registration_user_and_sign_in
end
scope "/api", MateriaWeb do
pipe_through [ :api, :pw_reset_auth]
get "/varidation-pw-reset", AuthenticatorController, :is_varid_token
post "/reset-my-password", UserController, :reset_my_password
end
scope "/api", MateriaWeb do
pipe_through [ :api, :guardian_auth]
get "/user", UserController, :show_me
post "/grant", GrantController, :get_by_role
post "/sign-out", AuthenticatorController, :sign_out
get "/auth-check", AuthenticatorController, :is_authenticated
post "/search-users", UserController, :list_users_by_params
resources "/addresses", AddressController, except: [:new, :edit]
post "/create-my-addres", AddressController, :create_my_address
end
〜中略〜
#今回はいらないのでコメントアウト
#scope "/", MateriaSampleWeb do
# pipe_through :browser # Use the default browser stack
#
# get "/", PageController, :index
#end
end
phoenixを起動する
> mix phx.server
※ ここからは自分の好きなHTTPクライアントを使用してください。
サンプルはREST Clientで記載しています。
VS Code上でHTTPリクエストを送信し、VS Code上でレスポンスを確認できる「REST Client」拡張の紹介
ログインする
- Request
POST http://localhost:4000/api/sign-in HTTP/1.1
Content-Type: application/json
{
"email": "hogehoge@example.com",
"password": "hogehoge"
}
- Response
HTTP/1.1 201 Created
server: Cowboy
date: Fri, 14 Dec 2018 08:16:32 GMT
content-length: 740
content-type: application/json; charset=utf-8
cache-control: max-age=0, private, must-revalidate
{
"refresh_token": "hogehoge",
"id": 1,
"access_token": "fugafuga"
}
ユーザー情報を確認する
- Request
GET http://localhost:4000/api/user HTTP/1.1
Content-Type: application/json
Authorization: Bearer fugafuga
- Response
HTTP/1.1 200 OK
server: Cowboy
date: Fri, 14 Dec 2018 08:21:53 GMT
content-length: 941
content-type: application/json; charset=utf-8
cache-control: max-age=0, private, must-revalidate
{
"status": 1,
"role": "admin",
"phone_number": null,
"organization": {
"users": [],
"status": 1,
"profile_img_url": "https://hogehoge.com/prof_img.jpg",
"phone_number": null,
"one_line_message": "let's do this.",
"name": "hogehoge.inc",
"lock_version": 1,
"id": 1,
"hp_url": "https://hogehoge.inc",
"back_ground_img_url": "https://hogehoge.com/ib_img.jpg",
"addresses": []
},
"name": "hogehoge",
"lock_version": 2,
"id": 1,
"icon_img_url": null,
"external_user_id": null,
"email": "hogehoge@example.com",
"descriptions": null,
"back_ground_img_url": null,
"addresses": [{
"zip_code": "810-ZZZZ",
"user": [],
"subject": "billing",
"organization": [],
"longitude": null,
"lock_version": 0,
"location": "福岡県",
"latitude": null,
"id": 2,
"address2": "大名 x-x-xx",
"address1": "福岡市中央区"
}, {
"zip_code": "810-ZZZZ",
"user": [],
"subject": "living",
"organization": [],
"longitude": null,
"lock_version": 0,
"location": "福岡県",
"latitude": null,
"id": 1,
"address2": "港 x-x-xx",
"address1": "福岡市中央区"
}]
}
他のユーザーに対する汎用検索を実施
- Request
### ユーザー汎用検索
POST http://localhost:4000/api/search-users HTTP/1.1
Content-Type: application/json
Authorization: Bearer fugafuga
{
"and": [{"role": "admin"}],
"or": [{"status": 8}, {"status": 1}]
}
- Response
[{
"status": 1,
"role": "admin",
"phone_number": null,
"organization": {
"users": [],
"status": 1,
"profile_img_url": "https://hogehoge.com/prof_img.jpg",
"phone_number": null,
"one_line_message": "let's do this.",
"name": "hogehoge.inc",
"lock_version": 1,
"id": 1,
"hp_url": "https://hogehoge.inc",
"back_ground_img_url": "https://hogehoge.com/ib_img.jpg",
"addresses": []
},
"name": "hogehoge",
"lock_version": 2,
"id": 1,
"icon_img_url": null,
"external_user_id": null,
"email": "hogehoge@example.com",
"descriptions": null,
"back_ground_img_url": null,
"addresses": []
}]
ログアウトする
- Request
POST http://localhost:4000/api/sign-out HTTP/1.1
Content-Type: application/json
Authorization: Bearer fugafuga
- Response
HTTP/1.1 200 OK
server: Cowboy
date: Fri, 14 Dec 2018 08:41:12 GMT
content-length: 11
content-type: application/json; charset=utf-8
cache-control: max-age=0, private, must-revalidate
{
"ok": true
}
再度ログインせずに実行すると認証エラー
- Request
### ユーザー汎用検索
POST http://localhost:4000/api/search-users HTTP/1.1
Content-Type: application/json
Authorization: Bearer fugafuga
{
"and": [{"role": "admin"}],
"or": [{"status": 8}, {"status": 1}]
}
- Response
HTTP/1.1 401 Unauthorized
server: Cowboy
date: Fri, 14 Dec 2018 08:42:26 GMT
content-length: 27
cache-control: max-age=0, private, must-revalidate
{"message":"invalid_token"}