私が探していることは、ユーザーがindex.htmlページに来たとき、私はログインモジュールが2つのことをする必要がある:
ユーザーが有効なトークンを持っている場合、ユーザーが認証されているかどうかを確認するためにこれが必要です(すでに「function authService」で開始していると思います)。または、キーがまったくない場合は、login/login.htmlをui-viewにロードします。
彼らが正常にログインしたら、「dashboard/dashboard.html」にルーティングされるようにしたい
ログインスクリプトを次に示します。
function authInterceptor(API) {
return {
request: function(config) {
if(config.url.indexOf(API) === 0) {
request.headers = request.headers || {};
request.headers['X-PCC-API-TOKEN'] = localStorage.getItem('token');
}
return config;
}
}
}
function authService(auth) {
var self = this;
self.isAuthed = function() {
localStorage.getItem('token');
}
}
function userService($http, API) {
$http.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;';
$http.defaults.transformRequest = [function(data) {
return angular.isObject(data) && String(data) !== '[object File]' ? param(data) : data;
}];
var self = this;
self.login = function(username, pwd, ctrl) {
ctrl.requestdata = API + '/winauth' + '; with ' + username;
return $http.post(API + '/winauth', {
username: username,
pwd: pwd
})
};
var param = function(obj) {
var query = '', name, value, fullSubName, subName, subValue, innerObj, i;
for(name in obj) {
value = obj[name];
if(value instanceof Array) {
for(i=0; i<value.length; ++i) {
subValue = value[i];
fullSubName = name + '[' + i + ']';
innerObj = {};
innerObj[fullSubName] = subValue;
query += param(innerObj) + '&';
}
}
else if(value instanceof Object) {
for(subName in value) {
subValue = value[subName];
fullSubName = name + '[' + subName + ']';
innerObj = {};
innerObj[fullSubName] = subValue;
query += param(innerObj) + '&';
}
}
else if(value !== undefined && value !== null)
query += encodeURIComponent(name) + '=' + encodeURIComponent(value) + '&';
}
return query.length ? query.substr(0, query.length - 1) : query;
};
}
function LoginCtrl(user) {
var self = this;
function handleRequest(res) {
self.responsedata = res;
self.message = res.data.message;
var authToken = res.data.auth_token;
localStorage.setItem('token', authToken);
}
self.login = function() {
this.requestdata = 'Starting request...';
user.login(self.username, self.pwd, self)
.then(handleRequest, handleRequest)
}
}
// Login Module
var login = angular.module('login', ["ui.router"])
login.factory('authInterceptor', authInterceptor)
login.service('user', userService)
login.service('auth', authService)
login.constant('API', 'http://myserver.com/api')
編集-ログインルートを提供するためにこれをログインコントローラーに追加しました
login.config(function($httpProvider, $stateProvider, $urlRouterProvider) {
$httpProvider.interceptors.Push('authInterceptor');
$urlRouterProvider.otherwise('/login');
$stateProvider
// HOME STATES AND NESTED VIEWS ========================================
.state('login', {
url: '/login',
templateUrl: 'login/login.html',
controller: "mainLogin",
controllerAs: "log"
})
// nested list with just some random string data
.state('dashboard', {
url: '/dashboard',
templateUrl: 'dashboard/dashboard.html',
})
})
login.controller('mainLogin', LoginCtrl)
ここに私のindex.htmlがあります:
編集-ルートを制御するために「ng-include」を削除し、「ng-view」を追加しました。
<body ng-app="login" ng-controller="mainLogin as log" class="loginPage">
<div class="main" ui-view></div>
</body>
ご覧のように、ユーザーのローカルストレージでトークンをチェックする機能があります。
function authService(auth) {
var self = this;
self.isAuthed = function() {
localStorage.getItem('token');
}
}
そして、私はそれをサービスとしてモジュールにロードしています:
login.service('auth', authService)
これは私が立ち往生している場所です。ここからどこへ行くのかわかりません。 authService関数を適切に使用しているかどうかさえわかりません。私はまだAngularJSについて多くのことを学んでいるので、簡単に行き詰まってしまいます。 :)
もう1つ気付くのは、index.htmlファイルにある「login/login.html」パーシャルをデフォルトとしてロードしていることです。ログインしているかどうかに応じて、login.htmlまたはdashboard.htmlをロードする必要があります。そして、ログインに成功したら、それらをdashboard.htmlにルーティングします。
このスクリプトは、認証APIにアクセスし、ユーザーを認証してから、有効な認証キーをローカルストレージに保存する限り、非常に機能します。
誰も私がこれを達成する方法を知っていますか?
ui.routerを使用していることがわかりましたので、このフレームワーク内で作業しましょう。
あなたはしたい
探しているのはresolve:{loggedIn: checkLoggedInFn}
ダッシュボードのルートは次のようになります
.state('dashboard', {
url: '/dashboard',
templateUrl: 'dashboard/dashboard.html',
resolve: {
loggedIn: function(){
//do your checking here
}
}
})
これは基本的に、すべての解決が解決されるまでコントローラーがインスタンス化しないため(たとえばここでプロミスを使用できます)、パラメーターとしてコントローラーに値が渡されるため、次のようなことができます:
if(!loggedIn){
$state.go('login');
}
あなたが扱っている2つの別々の懸念があります。 1つ目は、ログインしているかどうかを判断できることです。ユーザーがログイン状態以外の状態でログインする必要がある場合、$ stateChangeStateイベントをリッスンし、ユーザーがログインしていることを確認することで実装しますに:
login.run(function($state, authService) {
$rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams) {
var authToken = authService.isAuthed();
if (!authToken && toState !== 'login') {
//not logged in, so redirect to the login view instead of the view
//the user was attempting to load
event.preventDefault();
$state.go('login');
}
})
});
これにより、まだログインしていない場合はログイン状態になります。
2番目の部分は、ログイン後に正しいビューにリダイレクトすることです。これは、ログインコントローラーで行います。
function LoginCtrl(user, $state) {
var self = this;
function handleRequest(res) {
self.responsedata = res;
self.message = res.data.message;
var authToken = res.data.auth_token;
localStorage.setItem('token', authToken);
//after successful login, redirect to dashboard
$state.go('dashboard');
}
self.login = function() {
this.requestdata = 'Starting request...';
user.login(self.username, self.pwd, self)
.then(handleRequest, handleRequest)
}
}
ログインコントローラー内のロジックは、特にここで処理します。
self.login = function() {
this.requestdata = 'Starting request...';
user.login(self.username, self.pwd, self)
.then(handleRequest, handleRequest)
}
ログイン成功時のコールバック内で、状態を変更してユーザーを正しい状態に戻すだけです。
あなたのサービスは正常であり、loginModuleにありますが、私が見ることができる場所では使用していません。必要なことを行うには、コントローラーにサービスを注入する必要があります。 authServiceでは、localstorageからアイテムを取得していますが、たとえばログインサービスがある場合は何も返していません
function authService(auth) {
var self = this;
self.isAuthed = function() {
return localStorage.getItem('token');
}
}
//here you can inject your auth service to get it work as you want
function LoginCtrl(user, auth) {
var self = this;
function handleRequest(res) {
self.responsedata = res;
self.message = res.data.message;
var authToken = res.data.auth_token;
localStorage.setItem('token', authToken);
}
self.login = function() {
this.requestdata = 'Starting request...';
user.login(self.username, self.pwd, self)
.then(handleRequest, handleRequest)
}
}
login.service('auth', authService)
function authService(auth) {
var self = this;
self.isAuthed = function() {
**localStorage.getItem('token');**
}
}
localstorageアイテムはどこにありますか? LValueが欠落しています。
最も基本的なレベルでは、ダッシュボードページで、ページの読み込み時、つまりnullである場合、このアイテム(トークン)のチェックを処理できます。空の場合は、ユーザーをログインページにリダイレクト/ルーティングします。ところで、ブラウザセッションが閉じられるとすぐに前者がフラッシュされるため、 localStorage ではなくsessionStorageを使用します。
パスポート のような、よりエレガントでシンプルな方法があります。確認しましたか?これは次のように簡単です。
app.post('/login', passport.authenticate('local', { successRedirect: '/',
failureRedirect:'/login'}));
PassportJs を使用して、アプリケーションに必要なものを実現する簡単な方法があります。
ドキュメントは非常にシンプルで実装が簡単です。
このチュートリアル を参照して、Passportを使用した認証を実装することもできます。このチュートリアルでは、アプリケーションの認証方法を非常に簡単な方法で説明します。
コードは、URLの変更をチェックしていないか、横断的な方法でルートに影響を与えていません。
認証と承認は分野横断的な懸念事項であることを忘れないでください。つまり、Angularには、$ routeChangeStartをリッスンすることでルーティングコールをインターセプトする方法があります。そこに「インターセプター」を追加する必要があります。その後、手動でルーターを必要なビューにリダイレクトできます 前のスタックオーバーフロースレッド からのソリューションとして見てください。
authInterceptorに応答コードを追加します。そう:
return {
request: function(config) {
if(config.url.indexOf(API) === 0) {
request.headers = request.headers || {};
request.headers['X-PCC-API-TOKEN'] = localStorage.getItem('token');
}
return config;
},
response: function(response) {
//ok response - code 200
return response;
},
responseError: function(response){
//wrong response - different response code
}
};
サーバー側でhttpヘッダーを確認しますX-PCC-API-TOKENそして、間違っている場合(認証なし)レスポンスには403のような異なるコードが必要です。したがって、responseErrorメソッドはインターセプターで実行されます。
responseError: function(response){
//wrong response - different response code
if (response.status === 403) {
alert("No rights to page");//your code for no auth
//redirect to different route
$injector.get('$state').transitionTo('login');//use injector service
return $q.reject(response);//return rejection - use $q
}
}
それを行う簡単な方法は、単に https://github.com/Emallates/ng-enoa-auth パッケージを使用することです。アプリに含めるだけで、それ以外は必要ありません。