Laravel 自体は、PHP によって駆動されるマルチページアプリケーションの場合、完全なユーザー認証ソリューションを提供します。Laravel はユーザー認証の問題を完全に解決できます。しかし、SPA では、laravel は API サーバーに縮退し、ページのルーティングとフォームの送信はフロントエンド フレームワークによって完全に制御されます。この時点で、次の 2 つの問題に直面します:
フロントエンドでページのアクセス制御を実装する方法。
Ajax リクエストを承認するにはどうすればよいですか?
フロントエンドでページアクセス制御を実装するにはどうすればよいですか?
Ember.js 1.13.0 には認証機能がありません。ember-simple-auth というサードパーティの拡張機能を使用しました。これはその Github ホームページです:
https://github.com/simplabs/ember-simple-auth
まず、ember-cli プロジェクトのルート ディレクトリに拡張機能をインストールします:
ember install ember-cli-simple-auth
次に Configure でember/config/environment.js ファイルで、具体的な設定オプションについて詳しく説明しています。私の設定は次のとおりです。
// ember/config/environment.jsENV['simple-auth'] = { authorizer: 'authorizer:custom' //我使用了一个自定义的授权模块};
Ember-simple-auth は、Whenルートは特定のミックスインを継承し、その事前定義された動作または機能の一部を取得します。たとえば、私の ember/app/routes/application.js の内容は次のとおりです。
// ember/app/routes/application.js import ApplicationRouteMixin from 'simple-auth/mixins/application-route-mixin';export default Ember.Route.extend(ApplicationRouteMixin, { actions: { invalidateSession: function() { this.get('session').invalidate(); } }});
application-route-mixin には一連のアクション メソッドが事前定義されています。セッション上のイベントがトリガーされると、イベントを処理するために対応するアクションが呼び出されます。 ember/app/routes/application.js の独自のアクションでこれらのメソッドをオーバーライドすることもできます (ember-simple-auth は、フロントエンドによって生成されたすべての認証情報を保存する localStorage にセッション オブジェクトを維持します)。
次に、認証されたユーザーのみがアクセスできるページルートに、authenticated-route-mixin を追加します。
// ember/app/routes/user.js import AuthenticatedRouteMixin from 'simple-auth/mixins/authenticated-route-mixin';export default Ember.Route.extend(AuthenticatedRouteMixin,{ model: function(params) { return this.store.find('user',params.user_id); }});
authenticated-route-mixin により、認証されたユーザーのみが /user にアクセスできるようになります。許可されていない場合、デフォルトのリダイレクトは /login になります。したがって、認証なしでパスにアクセスできるようにするには、 unauthenticated-route-mixin を ember/app/routes/login.js:
// ember/app/routes/login.js import UnauthenticatedRouteMixin from 'simple-auth/mixins/unauthenticated-route-mixin';export default Ember.Route.extend(UnauthenticatedRouteMixin);
unauthenticated-route-mixin に追加する必要があります。これは /login にとって適切です。
Ajax リクエストを承認するにはどうすればよいですか?
カスタム認証子: ember/app/authenticators/custom.js
// ember/app/authenticators/custom.jsimport Base from 'simple-auth/authenticators/base';export default Base.extend({ /** * Check auth state of frontend * * @param data (传入session包含的数据) * @returns {ES6Promise.Promise} */ restore: function(data) { return new Ember.RSVP.Promise(function(resolve, reject) { if ( data.is_login ){ resolve(data); } else{ reject(); } }); }, /** * Permission to login by frontend * * @param obj credentials * @returns {ES6Promise.Promise} */ authenticate: function(credentials) { var authUrl = credentials.isLogin ? '/auth/login' : '/auth/register' return new Ember.RSVP.Promise(function(resolve, reject) { Ember.$.ajax({ url: authUrl, type: 'POST', data: { email: credentials.identification, password: credentials.password } }).then(function(response) { if(response.login === 'success'){ resolve({ is_login : true }); } }, function(xhr, status, error) { reject(xhr.responseText); }); }); }, /** * Permission to logout by frontend * * @returns {ES6Promise.Promise} */ invalidate: function() { return new Ember.RSVP.Promise(function(resolve) { Ember.$.ajax({ url: '/auth/logout', type: 'GET' }).then(function(response) { if(response.logout === 'success'){ resolve(); } }); }); }});
restore、authenticate、invalidate の 3 つの関数をそれぞれ認可の取得、認可、認可のキャンセルに使用します。
カスタムオーソライザー: ember/app/authorizers/custom.js
// ember/app/authorizers/custom.jsimport Base from 'simple-auth/authorizers/base';export default Base.extend({ authorize: function(jqXHR, requestOptions) { var _this = this; Ember.$.ajaxSetup({ headers: { 'X-XSRF-TOKEN': Ember.$.cookie('XSRF-TOKEN') // 防止跨域攻击 }, complete : function(response, state) { // 检查服务器的授权状态 if(response.status===403 && _this.get('session').isAuthenticated) { _this.get('session').invalidate(); } } }); }});
authorize 関数は 2 つのことを行います:
各 ajax リクエストに 'X-XSRF-TOKEN' ヘッダーを追加します
サーバーが返す認証ステータスを確認し、処理
?? 具体的には: ??
ヘッダーの内容は、laravel によって設定された 'XSRF-TOKEN' Cookie の値です。Laravel はヘッダー ('X-XSRF -TOKEN') を読み取ろうとします。トークンの値が正当である場合、チェックに合格した場合、それは安全なリクエストとみなされます (この関数は laravel/app/Http/Middleware/VerifyCsrfToken.php に実装されています)。
次に、laravel で新しいミドルウェア (ミドルウェア) を作成し、VerifyAuth という名前を付けました。
<?php// laravel/app/Http/Middleware/VerifyAuth.phpnamespace App\Http\Middleware;use Closure;use Illuminate\Contracts\Auth\Guard;class VerifyAuth{ protected $include = ['api/*']; // 需要做权限验证的 URL protected $auth; public function __construct(Guard $auth) { $this->auth = $auth; } /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @abort 403 * @return mixed */ public function handle($request, Closure $next) { if( $this->shouldPassThrough($request) || $this->auth->check() ) { return $next($request); } abort(403, 'Unauthorized action.'); //抛出异常,由前端捕捉并处理 } /** * Determine if the request has a URI that should pass through auth verification. * * @param \Illuminate\Http\Request $request * @return bool */ protected function shouldPassThrough($request) { foreach ($this->include as $include) { if ($request->is($include)) { return false; } } return true; }}
AUTH リクエストは権限操作であるため、API リクエストの権限検証のみを行います。その他のリクエストは、フロントエンドを無効なリクエストとして認識しないと、エラーがスローされます。リクエストが承認されていない場合、サーバーは 403 エラーをスローして、ユーザーがログインまたは登録する必要があることをフロントエンドに通知します。
最後に、すべての認可ロジックをlaravelappHttpControllersAuthAuthController.phpに実装します:
<?phpnamespace App\Http\Controllers\Auth;use App\User;use Validator;use Response;use Auth;use Illuminate\Http\Request;use App\Http\Controllers\Controller;use Illuminate\Foundation\Auth\ThrottlesLogins;use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;class AuthController extends Controller{ use AuthenticatesAndRegistersUsers, ThrottlesLogins; protected $remember = true; // 是否长期记住已登录的用户 public function __construct() { $this->middleware('guest', ['except' => 'getLogout']); } public function postLogin(Request $credentials) // 登录 { return $this->logUserIn($credentials); } public function getLogout() // 登出 { Auth::logout(); return Response::json(['logout'=>'success']); } public function postRegister(Request $credentials) // 创建并注册新用户 { $newUser = new User; $newUser->email = $credentials['email']; $newUser->password = bcrypt($credentials['password']); $newUser->save(); return $this->logUserIn($credentials); } protected function logUserIn(Request $credentials) // 实现用户登录 { $loginData = ['email' => $credentials['email'], 'password' => $credentials['password']]; if ( Auth::attempt($loginData, $this->remember) ) { return Response::json(['login'=>'success']); } else { return Response::json(['login'=>'failed']); } }}
概要
ページアクセス許可を設定すると、権限のないユーザーが自分に属していないページにアクセスするのを防ぐことができますが、最終的にはフロントend はユーザーに完全に公開されるため、ユーザーの承認ステータスはサーバーによって維持される必要があります。一方では、フロントエンドは各 ajax リクエストに対するクロスドメイン攻撃を防ぐためにトークンを追加します。他方では、各リクエストが返されると、http ステータス コードが 403 パーミッション エラーであるかどうかを確認し、そうである場合はリダイレクトします。ログイン ページにアクセスして、ユーザーに承認の取得を要求します。