บทเรียน AngularJS สำหรับผู้เริ่มต้นศึกษา ในตอนนี้จะนำเสนอส่วนของการทำ Login System ที่ต้องมีการดึงข้อมูลการเข้าระบบผ่าน API มาและใช้ร่วมกับ Session
บทเรียนสำหรับให้ศึกษาก่อนหน้านี้
- การเขียน Single Page Application ด้วย AngularJS
- AngularJS กับการวนซ้ำข้อมูลด้วย ng-repeat และกรองด้วย Filter
- AngularJS การแยก Controller และทำงานร่วมกับ Table
- AngularJS กับการทำงานร่วมกับ Web Service JSON
- AngularJS กับ POST ข้อมูลลง MySQL ผ่าน Web Service
- AngularJS กับการ GET ข้อมูล http เพื่อเปลี่ยนหน้าด้วย $location
- AngularJS การ Edit ข้อมูลรายการผ่าน Web Service และ MySQL
สำหรับการทำระบบ Login ของ AngularJS นั้นจะเอาไปฝัง On Page แบบ Javascript ดาดเดือดทั่วไปก็คงจะไม่เหมาะครับ มันดูเอารถ Volvo ไปขายไอติม ถ้ามันทำงานแบบ SPA แล้ว Key Value จึงเป้นสิ่งที่เราต้องคิดอันดับแรกๆ ดังนั้น เราต้องสร้าง API ขึ้นมาใหม่ครับ เป็น API ที่เกี่ยวกับการเข้าระบบ และ เก็บ Session การเข้าระบบโดย AngularJS ทำหน้าที่เป็น Front End ก็พอ
ให้เราไปสร้าง API ใหม่ชื่อว่า login_action() ด้วย PHP ไฟล์ login_action.php ครับ
<?php $postdata = file_get_contents("php://input"); $request = json_decode($postdata); @$username = $request->username; @$password = $request->password; $charmap="1234ABCDEFGHIJKLMNOPQRSTUYWXYZabcdefghijklmnopqrstuvwxyz"; $codRandom = str_shuffle($charmap); include"db.php"; $strSQL = "SELECT * FROM administrator WHERE username = '".$username."' and password = '".$password."'"; $objQuery = mysql_query($strSQL); $objResult = mysql_fetch_array($objQuery); if(!$objResult){ echo 'false'; }else{ session_start(); $_SESSION["token"] = $codRandom; $_SESSION["username"] = $username; echo 'true, '.$_SESSION["token"] ; } mysql_close($objConnect); ?>
เป็นการรับค่าจาก Form ของ View โดยใช้ ng-model ที่ชื่อ Username และ Password มาแบบ Method POST ครับ
@$username = $request->username; @$password = $request->password;
ถ้าเราต้องเขียนส่วนของ API แล้ว เรื่องของ Security เป็นสิ่งจำเป็นครับ อันที่จริงการส่ง Parameter ต้องมี API_KEY ด้วยแต่ผมขอละมันไว้ก่อนไปหาวิธีทำเองนะครับ ผมจะมาเน้นในเรื่องของ Session ที่มี Access Token เป็น Key อ้างอิง ซึ่งผมใช้วิธีการสุ่ม Random String ออกมาจากฟังก์ชันนี้
$charmap="1234ABCDEFGHIJKLMNOPQRSTUYWXYZabcdefghijklmnopqrstuvwxyz"; $codRandom = str_shuffle($charmap);
ทำการ Check Username Password ด้วย SQL ปรกติถ้าตรงกับตารางของ driver ที่เราสร้างไว้แต่แรกก็ให้ทำการ เก็บ Session ครับ
session_start(); $_SESSION["token"] = $codRandom; $_SESSION["username"] = $username; echo 'true, '.$_SESSION["token"] ;
ทำการ echo ค่า true และ Access Token ออกมาเพื่อเอาไปเช็คที่หน้า Form ครับ ดังนั้นส่วนของการกดปุ่ม API ตอน Login เราจะเสร็จสมบูรณ์แล้ว ซึ่งจะได้ส่วนของ username และ access_token เก็บในลงใน Session
ต่อมาเราต้องทำหน้า Form ขึ้นมาครับเป็น View ใหม่ที่ชื่อ login.html
“อันที่จริงก็แค่เอาหน้า register.html มาแก้ก็เท่านั้น ใช่ไหม?”
ใส่ ng-app ชื่อ loginModules
<!doctype html> <html ng-app="loginModules"> <head> <meta charset="UTF-8"> <title>AngularJS</title> <link rel="stylesheet" href="css/bootstrap.min.css"> <script src="js/angular.min.js"></script> </head>
และ ng-controller ชื่อ loginController
<form ng-controller="loginController" name="regForm" novalidate> <p>Username:<br> <input class="form-control" type="text" name="first_name" ng-model="username" required> <span class="alert alert-danger" ng-show="regForm.username.$dirty && regForm.username.$invalid"> <span ng-show="regForm.first_name.$error.required">Username required.</span> </span> </p> <p>Password:<br> <input class="form-control" type="text" name="password" ng-model="password" required> <span class="alert alert-danger" ng-show="regForm.password.$dirty && regForm.password.$invalid"> <span ng-show="regForm.last_name.$error.required">Password is required.</span> </span> </p> <p> <input type="submit" value="Login" class="btn btn-sm btn-success" ng-click="login()" ng-disabled=" regForm.username.$dirty && regForm.username.$invalid || regForm.password.$dirty && regForm.password.$invalid"> </p> <p> <br/> <span id="message" class="alert alert-success">{{message}}</span> </p> </form>
ตามด้วย controller/login.js สร้างไฟล์ Controller ชื่อ login.js ขึ้นมา
<script src="controller/login.js"></script> </body> </html>
ไฟล์ login.html จะเป็นดังนี้
<!doctype html> <html ng-app="loginModules"> <head> <meta charset="UTF-8"> <title>AngularJS</title> <link rel="stylesheet" href="css/bootstrap.min.css"> <script src="js/angular.min.js"></script> </head> <body> <div class="container"> <ul class="nav nav-pills" role="tablist"> <li role="presentation" class="active"><a href="index.html">Home</a></li> <li role="presentation"><a href="register.html">Register</a></li> <li role="presentation"><a href="#job">Jobs Report</a></li> </ul> <h3>Add New Driver</h3> <div class="panel panel-primary"> <div class="panel-heading"> <h3 class="panel-title">Register: </h3> </div> <div class="panel-body"> <form ng-controller="loginController" name="regForm" novalidate> <p>Username:<br> <input class="form-control" type="text" name="first_name" ng-model="username" required> <span class="alert alert-danger" ng-show="regForm.username.$dirty && regForm.username.$invalid"> <span ng-show="regForm.first_name.$error.required">Username required.</span> </span> </p> <p>Password:<br> <input class="form-control" type="text" name="password" ng-model="password" required> <span class="alert alert-danger" ng-show="regForm.password.$dirty && regForm.password.$invalid"> <span ng-show="regForm.last_name.$error.required">Password is required.</span> </span> </p> <p> <input type="submit" value="Login" class="btn btn-sm btn-success" ng-click="login()" ng-disabled=" regForm.username.$dirty && regForm.username.$invalid || regForm.password.$dirty && regForm.password.$invalid"> </p> <p> <br/> <span id="message" class="alert alert-success">{{message}}</span> </p> </form> </div> </div> </div> <script src="controller/login.js"></script> </body> </html>
ส่วนของ controller ไฟล์ login.js นั้นจะใช้ Code ต่อไปนี้ครับ
angular.module('loginModules', []) .controller('loginController', function($scope,$http) { $scope.username = 'admin'; $scope.password = 'admin1234'; $scope.login = function () { $scope.message = ""; var request = $http({ method: "post", url: "api/login_action.php", data: { username: $scope.username, last_name: $scope.last_name, password: $scope.password }, headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }); request.success(function (data) { $scope.message = "Console : "+data; if(data=="false"){ alert("no"); }else{ alert("ok"); } }); } });
กดปุ่ม Submit เรียกฟังก์ชัน ใน $scope
$scope.login = function ()
ทำการทดสอบหน้าเว็บของเราครับ
ถ้า Login ถูก Alert ว่า “ok” ถ้าผิด alert ว่า “no”
Access Token เรียบร้อยแล้ว {รหัส ยาวมาก}
ทำการสร้าง API มาหนึ่งตัวครับชื่อว่า session() ไว้เช็คว่า ค่าคนที่ login อยู่มีค่าอะไรค้างใน session บ้าง
<?php session_start(); $access_username=$_SESSION['username']; $access_token=$_SESSION["token"]; $admin[] = array( 'status' => 'true', 'message' => 'this log in user', 'username' => $access_username, 'access_token' => $access_token ); header("Access-Control-Allow-Origin: *"); header("content-type:text/javascript;charset=utf-8"); header("Content-Type: application/json; charset=utf-8", true, 200); print json_encode(array("data"=>$admin)); ?>
ทดสอบยิง URL ตรงๆ เช็คหน่อยดีกว่า
message ในระบบเขียนอะไรก็ได้ แต่ username และ access_token ต้องใช้งานครับ เรามาสร้างหน้า ที่ต้องใช้ session ในการเข้าดู และสร้าง redirect page กรณีที่เรา Login เข้าระบบไม่ผ่านแล้วไปหน้า login.html ทันที ให้เรา View ขำๆ มา 1 หน้าครับ ชื่อ “session.html”
<!doctype html> <html ng-app="sessionModules"> <head> <meta charset="UTF-8"> <title>AngularJS</title> <link rel="stylesheet" href="css/bootstrap.min.css"> <script src="js/angular.min.js"></script> </head> <body> <div class="container" ng-controller="sessionController"> <ul class="nav nav-pills" role="tablist"> <li role="presentation" class="active"><a href="index.html">Home</a></li> <li role="presentation"><a href="register.html">Register</a></li> <li role="presentation"><a href="#job">Jobs Report</a></li> </ul> <h3>Driver Information</h3> <div class="panel panel-primary"> <div class="panel-heading"> <h3 class="panel-title">Register: </h3> </div> <div class="panel-body"> <ul class="list-group" ng-repeat="data in session"> <li class="list-group-item">First Name: {{data.username}}</li> <li class="list-group-item">Last Name: {{data.access_token}}</li> </ul> </div> </div> </div> <script src="controller/session.js"></script> </body> </html>
ประกอบไปด้วย ng-app ชื่อ sessionModles, ng-controller ชื่อ sessionController และ ไฟล์ controller ชื่อ session.js ไว้รับค่า session มาไว้ใน $scope ชื่อ session ไว้ repeat
ไฟล์ Controller ของ session.js เขียนดังนี้
angular.module('sessionModules', []) .controller('sessionController', function($scope, $http, $location, $window) { $http.get("http://localhost/AngularJS/api/session.php") .success(function (response) {$scope.session = response.data; $scope.access_token = response.data[0].access_token; if($scope.access_token == ""){ $window.location.href="login.html"; } }); });
ทดสอบกันหน่อยลองเข้าไปดูสิ
ถ้า Session ไม่มีไฟล์ session.html จะ Redirect ไปที่หน้า login.html ครับ
ส่วน logout ก็เอา Code API ของการ Clear Session ไปใช้ ตามด้วย $location ส่วนของ redirect ไปก็เป็นอันจบครับ