最近在改寫kibana,碰到了驗證登陸的問題。問題是這樣子的,nginx設置了basic認證,而後客戶端訪問kibana的時候老是會彈出登陸框,輸入用戶名和密碼,如今要改寫這個登錄框,用bootstrap來模擬一下登陸驗證。html
最終效果:前端
解決方案:首先看到請求的返回status是401,也就是未受權,能夠本身百度一下 `basic authentication`。咱們須要在node端把401的錯誤碼改爲其餘的,我這裏改爲了403。紅色部分是我後來加上的,文件路徑: `src/server/plugins/elasticsearch/lib/create_proxy.js`。這樣就不會彈出難看的認證框了。node
var createAgent = require('./create_agent'); var mapUri = require('./map_uri'); module.exports = function createProxy(server, method, route, opts) { opts = opts || {}; var options = { method: method, path: route, handler: { proxy: { mapUri: mapUri(server, opts.prefix), passThrough: true, agent: createAgent(server), onResponse:function(err, res, request, reply, settings, ttl){ if(res.statusCode==401){ res.statusCode =403; } reply(res); } } } }; if (opts && opts.config) options.config = opts.config; server.route(options); };
解決了nodejs端的狀態碼問題,如今該處理前端的展現方面了。nginx
看了kibana源碼,這裏引用了angularjs,那就好辦了,咱們能夠利用$httpProvider這個服務來寫一個攔截器。而後在request的時候,把本地存儲的用戶名和密碼寫到header中去,就模擬了basic驗證。文件路徑:src/kibana/plugins/kibana/index.jsangularjs
// ensure that the kibana module requires ui.bootstrap
require('modules')
.get('kibana', ['ui.bootstrap','ngCookies'])
.config(function ($tooltipProvider) {
$tooltipProvider.setTriggers({ 'mouseenter': 'mouseleave click' });
})
.factory('HttpInterceptorFactory', ['$rootScope', '$cookieStore', '$q', function ($rootScope, $cookieStore, $q) {
return {
'request': function (httpConfig) {
var up = $cookieStore.get('usernameandpassword');
up && (httpConfig.headers.Authorization = "Basic " + up);
return httpConfig;
}
};
}])
.config(['$httpProvider', function ($httpProvider) {
$httpProvider.interceptors.push('HttpInterceptorFactory');
}])
.controller('LoginController',function($scope,$cookieStore,$modalInstance){
$scope.username="";
$scope.password="";
$scope.ok = function (user,psw) {
$cookieStore.put("usernameandpassword", btoa(user +":"+psw));
location.reload();
};
})
.directive('kibana', function (Private, $rootScope,$timeout, $cookieStore,$injector, Promise, config, kbnSetup,$modal) {
return {
template: require('text!plugins/kibana/kibana.html'),
controllerAs: 'kibana',
controller: function ($scope) {
var _ = require('lodash');
var self = $rootScope.kibana = this;
var notify = new Notifier({ location: 'Kibana' });
// this is the only way to handle uncaught route.resolve errors
$rootScope.$on('$routeChangeError', function (event, next, prev, err) {
if(err.origError.status==403){
// location.hash="#/passport/login";
self.doLogin();
return;
}
notify.fatal(err);
});
self.doLogin = function(){
var modalInstance = $modal.open({
template: require('text!plugins/kibana/login.html'),
controller: 'LoginController',
size: 'sm',
backdrop:'static'
});
modalInstance.result.then(function (selectedItem) {
}, function () {
$log.info('Modal dismissed at: ' + new Date());
});
}
// run init functions before loading the mixins, so that we can ensure that
// the environment is ready for them to get and use their dependencies
self.ready = Promise.all([ kbnSetup(), config.init() ])
.then(function () {
// load some "mixins"
var mixinLocals = { $scope: $scope, notify: notify };
$injector.invoke(require('plugins/kibana/_init'), self, mixinLocals);
$injector.invoke(require('plugins/kibana/_apps'), self, mixinLocals);
$injector.invoke(require('plugins/kibana/_timepicker'), self, mixinLocals);
$scope.setupComplete = true;
});
}
};
});
<div class="modal-header"> <h3 class="modal-title">Login In</h3> </div> <div class="modal-body"> <div class="form-group"> <label >Username</label> <input style="border:1px solid;" type="text" ng-model="username" class="form-control" placeholder="Username"> </div> <div class="form-group"> <label >Password</label> <input style="border:1px solid;" type="password" ng-model="password" class="form-control" placeholder="Password"> </div> </div> <div class="modal-footer"> <button class="btn btn-primary" ng-click="ok(username,password)">Login</button> </div>
大功告成。我使用的kibana的版本是4.2.0,enjoy it。bootstrap