Tag Archive hash

Laravel: Basic API Token Authentication อย่างง่าย

ทำระบบ api ส่งข้อมูลให้ฝั่ง mobile ดึงข้อมูล บางส่วนมันไม่ใช่ความลับ จะทำระบบ authentication โหดๆ ก็เปลือง จะไม่ตรวจอะไรเลยก็ดูมันอ่อนไป สุดท้ายมาจบที่คำว่า basic API token คือ ขอแค่ส่ง token มาให้ถูกก็พอละจะได้ไม่โหลด server มาก ไว้ใช้กับส่วนที่เป็นการดึงข้อมูล common ๆ ง่ายๆ ที่ user ใช้ร่วมกันได้ไม่มีความลับอะไร

เริ่มจากทำ middleware ชื่อ apitoken ง่ายๆ มาใช้เอง

  1. ใช้ command สร้างขึ้นมา
    php artisan make:middleware ApiToken

    มันจะสร้างไฟล์ขึ้นมาใหม่ที่ \app\Http\Middleware

    <?php
    
    namespace App\Http\Middleware;
    
    use Closure;
    
    class ApiToken
    {
        /**
         * Handle an incoming request.
         *
         * @param  \Illuminate\Http\Request  $request
         * @param  \Closure  $next
         * @return mixed
         */
        public function handle($request, Closure $next)
        {
            return $next($request);
        }
    }
  2. แก้โดยให้อ่านค่ามาจาก Environment Configuration แล้วเทียบกับค่าที่ส่งมา ว่าตรงมั๋ย ตรงก็ปล่อยผ่อนไป ไม่ตรงก็อด
    <?php
    
    namespace App\Http\Middleware;
    
    use Closure;
    
    class ApiToken
    {
        /**
         * Handle an incoming request.
         *
         * @param  \Illuminate\Http\Request  $request
         * @param  \Closure  $next
         * @return mixed
         */
        public function handle($request, Closure $next)
        {
    
            if ($request->expectsJson()) {
    
                if (env('API_TOKEN') != $request->header('token')) {
                    return response('Unauthorized.', 401);
                }
    
            } else {
                return route('login');
            }
    
            return $next($request);
        }
    }
    

    เพิ่มขึ้นมาไม่กี่บรรทัดเอง

  3. เปิดไฟล์ .env มาเพิ่ม config token ที่ใช้เข้าไป
    ...
    API_TOKEN=a6b042ae282d91ab2c25bc7ae515af68
    ...
  4. กำหนด url ที่ใช้ basic token ง่ายๆของเราโดยการแก้ routing ตามแบบ
    Route::group([
        'middleware' => 'api.token',
        'prefix' => 'common',
    ], function () {
    
        Route::get('cars', 'CarsController@json');
    
    });

    ทุก route ที่อยู่ใน block นี้จะได้รับการปกป้องด้วย api.token

  5. แต่ตอนนี้ laravel ยังไม่รู้จักกับ api.token เราจะต้องไปเปิดไฟล์ \app\Http\Kernel.php และเพิ่ม $routeMiddleware ตามตัวอย่าง
        protected $routeMiddleware = [
    ...
            'api.token' => \App\Http\Middleware\ApiToken::class,
    ...
        ];

เทสโดยใช้ Postman เรียก url ตามเดิม แต่จะมี common เพิ่มเข้ามาเพราะเพิ่มไปใน route เช่น http://localhost/prototype_laravel/public/api/cars แก้เป็น http://localhost/prototype_laravel/public/api/common/cars และต้องส่ง header ไปโดยมี

  • Accept application/json
  • token a6b042ae282d91ab2c25bc7ae515af68c

มาพร้อมๆ กันถึงจะสามารถ call api ตัวนี้ได้สำเร็จ ไม่งั้นจะเจอกับ Unauthorized.

Bootstrap: dynamic tabs hash

เพราะว่า dynamic tabs ของ Bootstrap มันจะไม่เลือก tabs จาก hash หรือเครื่องหมาย # ใน url ถ้าต้องการให้แสดงแท็บที่ต้องการจาก links ต้องเขียน code เพิ่มเติมอีกเล็กน้อย

<!doctype html>
<html>

<head>
<meta charset="utf-8">
<title>Bootstrap: Dynamic Tabs With Hash</title>
<link href="../vendor/twbs/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet" type="text/css">
</head>

<body>
<div class="container">
<h2>Dynamic Tabs With Hash</h2>

<input id="tabindex" name="tabindex" type="text">

<ul class="nav nav-tabs">

<li class="nav-item">
<a class="active nav-link show" data-toggle="tab" href="#menu1">Menu 1</a>
</li>

<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#menu2">Menu 2</a>
</li>

<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#menu3">Menu 3</a>
</li>
</ul>

<div class="tab-content">

<div id="menu1" class="active fade in show tab-pane">
<h3>Menu 1</h3>
<p>นาย</p>
</div>

<div id="menu2" class="fade tab-pane">
<h3>Menu 2</h3>
<p>พิชญ์</p>
</div>

<div id="menu3" class="fade tab-pane">
<h3>Menu 3</h3>
<p>พันธุ์สนิท</p>
</div>

</div>

</div>

<script src="../vendor/components/jquery/jquery.min.js"></script>
<script src="../vendor/twbs/bootstrap/dist/js/bootstrap.min.js"></script>
<script>
$(document).ready(function () {

let hash = window.location.hash.substr(1);
let tabindex = $('#tabindex');
if (hash != tabindex.val()) {
$('a[href="#' + hash).click();
tabindex.val(hash);
}

});
</script>

</body>

</html>

เมื่อเปิดหน้าเว็บมาจาก url ที่ใส่ # ของแท็บที่ต้องการมา เช่น http://localhost/snippets/Bootstrap/tabs.dynamic.hash.html#menu2 แท็บก็จะเปิดหน้าที่ถูกต้องตามที่ต้องการ แทนที่จะดูจาก class active เพียงอย่าเดียว

Joget: แสดงเซ็กชั่นฟอร์มแบบแท็บ

การกำหนดให้แสดง section ของฟอร์มโดยเปลี่ยนค่าใน input เหมือน Joget: กำหนดการแสดงไม่แสดง section ด้วย input มันไม่ค่อยจะเป็นธรรมชาติเท่าไหร่ ผู้ใช้จะคุ้นเคยกับ tabs มากกว่า

ทำได้โดย

  1. ให้ทำตามวิธี Joget: กำหนดการแสดงไม่แสดง section ด้วย input ก่อน
  2. ให้ลาก Custom HTML มาในตำแหน่งที่ต้องการ ใส่ javascript ตามตัวอย่าง
    <ul class="nav nav-tabs" id="tabsA">
    <li class="nav-item">
    <a class="active nav-link show" data-toggle="tab" href="#section1">Section 1</a>
    </li>
    <li class="nav-item">
    <a class="nav-link" data-toggle="tab" href="#section2">Section 2</a>
    </li>
    <li class="nav-item">
    <a class="nav-link" data-toggle="tab" href="#section3">Section 3</a>
    </li>
    </ul>
    <script src="/jw/assets/scripts.js"></script>
    <script>
    $(document).ready(function() {
    
    navSection();
    
    });
    </script>
  3. ไฟล์ javascript ที่เก็บ function แยกเอาไว้ reused ได้หลายๆ ครั้ง
    /*
    pitt phunsanit
    show / hide section with tabs
    version 1
    */
    function navSection() {
    let hash = window.location.hash.substr(1);
    let visibilityControl = $("#visibilityControl");
    let tabsA = $("#tabsA");
    
    if (hash != visibilityControl.val()) {
    $('a[href="#' + hash).click();
    visibilityControl.val(hash);
    }
    
    $("li > a", tabsA).on("click", function() {
    visibilityControl
    .val(
    $(this)
    .attr("href")
    .substr(1)
    )
    .trigger("change");
    });
    }

การแสดงไม่แสดง form section จะเห็นเป็น tabs ธรรมดาๆ ดูเป็นธรรมชาติขึ้นมากกว่าเดิม ตัวอย่างฟอร์ม

{"className":"org.joget.apps.form.model.Form","properties":{"id":"sectionTabs","loadBinder":{"className":"org.joget.apps.form.lib.WorkflowFormBinder"},"tableName":"prototypes","description":"","name":"Section Tabs","storeBinder":{"className":"org.joget.apps.form.lib.WorkflowFormBinder"}},"elements":[{"elements":[{"elements":[{"className":"org.joget.apps.form.lib.HiddenField","properties":{"id":"visibilityControl","workflowVariable":"","value":"section1","useDefaultWhenEmpty":""}},{"className":"org.joget.apps.form.lib.CustomHTML","properties":{"id":"dynamicTabsA","autoPopulate":"","value":"<ul class=\"nav nav-tabs\" id=\"tabsA\">\n    <li class=\"nav-item\">\n        <a class=\"active nav-link show\" data-toggle=\"tab\" href=\"#section1\">Section 1<\/a>\n    <\/li>\n    <li class=\"nav-item\">\n        <a class=\"nav-link\" data-toggle=\"tab\" href=\"#section2\">Section 2<\/a>\n    <\/li>\n    <li class=\"nav-item\">\n        <a class=\"nav-link\" data-toggle=\"tab\" href=\"#section3\">Section 3<\/a>\n    <\/li>\n<\/ul>\n<script src=\"\/jw\/assets\/scripts.js\"><\/script>\n<script>\n    $(document).ready(function() {\n\n        navSection();\n\n    });\n<\/script>","label":""}}],"className":"org.joget.apps.form.model.Column","properties":{"width":"100%"}}],"className":"org.joget.apps.form.model.Section","properties":{"id":"section1","loadBinder":{"className":"","properties":{}},"visibilityControl":"","regex":"","visibilityValue":"","storeBinder":{"className":"","properties":{}},"permission":{"className":"","properties":{}},"label":""}},{"elements":[{"elements":[{"className":"org.joget.apps.form.lib.TextField","properties":{"id":"field1","readonlyLabel":"","workflowVariable":"","maxlength":"","encryption":"","validator":{"className":"","properties":{}},"value":"","label":"Section 1","readonly":"","size":""}}],"className":"org.joget.apps.form.model.Column","properties":{"width":"100%"}}],"className":"org.joget.apps.form.model.Section","properties":{"id":"section1","loadBinder":{"className":"","properties":{}},"visibilityControl":"visibilityControl","regex":"","visibilityValue":"section1","storeBinder":{"className":"","properties":{}},"permission":{"className":"","properties":{}},"label":"Section 1"}},{"elements":[{"elements":[{"className":"org.joget.apps.form.lib.TextField","properties":{"id":"field2","readonlyLabel":"","workflowVariable":"","maxlength":"","encryption":"","validator":{"className":"","properties":{}},"value":"","label":"Section 2","readonly":"","size":""}}],"className":"org.joget.apps.form.model.Column","properties":{"width":"100%"}}],"className":"org.joget.apps.form.model.Section","properties":{"id":"section2","loadBinder":{"className":"","properties":{}},"visibilityControl":"visibilityControl","regex":"","visibilityValue":"section2","storeBinder":{"className":"","properties":{}},"permission":{"className":"","properties":{}},"label":"Section 2"}},{"elements":[{"elements":[{"className":"org.joget.apps.form.lib.TextField","properties":{"id":"field3","readonlyLabel":"","workflowVariable":"","maxlength":"","encryption":"","validator":{"className":"","properties":{}},"value":"","label":"Section 3","readonly":"","size":""}}],"className":"org.joget.apps.form.model.Column","properties":{"width":"100%"}}],"className":"org.joget.apps.form.model.Section","properties":{"id":"section3","loadBinder":{"className":"","properties":{}},"visibilityControl":"visibilityControl","regex":"","visibilityValue":"section3","storeBinder":{"className":"","properties":{}},"permission":{"className":"","properties":{}},"label":"Section 3"}}]}