文章目录 [+]
前言
在使用laravel-admin的途中,尽管不错,但是登录时没有验证码这一直是我心里不爽的一点,出于安全的考虑,于是打算整合一个极验证到我的项目当中去。
Geetest
这是我所用的极验证,目测还凑合吧,暂时先用着。
laravel-admin整合极验证
安装
composer安装geetest的php-sdk。
composer require gee-team/gt-php-sdk
重构
当然我们要想使用geetest这个极验证的话,我们只能重构登录系统,那么跟着我下边的思路走,新建路由->新建AuthController->新建login.blade.php。
新建路由
Route::group ( [ 'prefix' => config ( 'admin.route.prefix' ) , 'namespace' => config ( 'admin.route.namespace' ) , ],function (Router $router){ $router->get('auth/start_captcha','AuthController@startCaptcha');//初始化极验证,这个必须不通过登录中间件验证,否则无法获取 }); Route::group ( [ 'prefix' => config ( 'admin.route.prefix' ) , 'namespace' => config ( 'admin.route.namespace' ) , 'middleware' => config ( 'admin.route.middleware' ) , ],function (Router $router){ $router->get('auth/login', 'AuthController@getLogin');//登录页面 $router->post('auth/login', 'AuthController@postLogin');//登录请求 });
新建AuthController控制器
将/vendor/encore/laravel-admin/src/Controllers/AuthController复制到/app/Admin/Controllers中,修改命名空间,以及编辑以下几个方法:getLogin(修改)、postLogin(修改)、startCaptcha(添加)、validateCaptcha(添加),如果懒得写,可以直接复制下边的代码:
<?php namespace App\Admin\Controllers; use Encore\Admin\Auth\Database\Administrator; use Encore\Admin\Facades\Admin; use Encore\Admin\Form; use Encore\Admin\Layout\Content; use Illuminate\Http\Request; use Illuminate\Routing\Controller; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Lang; use Illuminate\Support\Facades\Redirect; use Illuminate\Support\Facades\Validator; use GeetestLib; class AuthController extends Controller { public function __construct () { //打开session,如果打开了,可以删除 if(!isset($_SESSION)){ session_start (); } } /** * Show the login page. * * @return \Illuminate\Contracts\View\Factory|Redirect|\Illuminate\View\View */ public function getLogin () { if ( ! Auth::guard ( 'admin' )->guest () ) { return redirect ( config ( 'admin.route.prefix' ) ); } return view ( 'admin.login' ); } /** * Handle a login request. * * @param Request $request * * @return mixed */ public function postLogin ( Request $request ) { $credentials = $request->only ( [ 'username' , 'password' ] ); $validator = Validator::make ( $credentials , [ 'username' => 'required' , 'password' => 'required' , ] , [ 'username.required' => '用户名不能为空' , 'password.required' => '密码不能为空' ] ); if ( $validator->fails () ) { return Redirect::back ()->withInput ()->withErrors ( $validator ); } //验证极验证码 if ( ! $this->validateCaptcha () ) { return Redirect::back ()->withInput ()->withErrors ( [ 'captcha' => '验证失败:拖动滑块将悬浮图像正确拼合' ] ); } unset( $credentials[ 'captcha' ] ); if ( Auth::guard ( 'admin' )->attempt ( $credentials ) ) { admin_toastr ( trans ( 'admin.login_successful' ) ); return redirect ()->intended ( config ( 'admin.route.prefix' ) ); } return Redirect::back ()->withInput ()->withErrors ( [ 'username' => $this->getFailedLoginMessage () ] ); } /** * 初始化极验证 */ public function startCaptcha () { $GtSdk = new GeetestLib(); $return = $GtSdk->register (); if ( $return ) { $_SESSION['gtserver'] = 1; $result = array ( 'success' => 1 , 'gt' => CAPTCHA_ID , 'challenge' => $GtSdk->challenge ); echo json_encode ( $result ); } else { $_SESSION['gtserver'] = 0; $rnd1 = md5 ( rand ( 0 , 100 ) ); $rnd2 = md5 ( rand ( 0 , 100 ) ); $challenge = $rnd1 . substr ( $rnd2 , 0 , 2 ); $result = array ( 'success' => 0 , 'gt' => CAPTCHA_ID , 'challenge' => $challenge ); $_SESSION[ 'challenge' ] = $result[ 'challenge' ]; echo json_encode ( $result ); } die; } /** * 这里二次验证极验证是否正确 */ public function validateCaptcha () { // GeetestLib $GtSdk = new GeetestLib(); if ( $_SESSION[ 'gtserver' ] == 1 ) { $result = $GtSdk->validate ( $_POST[ 'geetest_challenge' ] , $_POST[ 'geetest_validate' ] , $_POST[ 'geetest_seccode' ] ); if ( $result == TRUE ) { return true; } else if ( $result == FALSE ) { return false; } else { return false; } } else { if ( $GtSdk->get_answer ( $_POST[ 'geetest_validate' ] ) ) { return true; } else { return false; } } } /** * User logout. * * @return Redirect */ public function getLogout ( Request $request ) { $this->guard ()->logout (); $request->session ()->invalidate (); return redirect ( config ( 'admin.route.prefix' ) ); } /** * User setting page. * * @return mixed */ public function getSetting () { return Admin::content ( function ( Content $content ) { $content->header ( trans ( 'admin.user_setting' ) ); $form = $this->settingForm (); $form->tools ( function ( Form\Tools $tools ) { $tools->disableBackButton (); $tools->disableListButton (); } ); $content->body ( $form->edit ( Admin::user ()->id ) ); } ); } /** * Update user setting. * * @return \Symfony\Component\HttpFoundation\Response */ public function putSetting () { return $this->settingForm ()->update ( Admin::user ()->id ); } /** * Model-form for user setting. * * @return Form */ protected function settingForm () { return Administrator::form ( function ( Form $form ) { $form->display ( 'username' , trans ( 'admin.username' ) ); $form->text ( 'name' , trans ( 'admin.name' ) )->rules ( 'required' ); $form->image ( 'avatar' , trans ( 'admin.avatar' ) ); $form->password ( 'password' , trans ( 'admin.password' ) )->rules ( 'confirmed|required' ); $form->password ( 'password_confirmation' , trans ( 'admin.password_confirmation' ) )->rules ( 'required' ) ->default ( function ( $form ) { return $form->model ()->password; } ); $form->setAction ( admin_base_path ( 'auth/setting' ) ); $form->ignore ( [ 'password_confirmation' ] ); $form->saving ( function ( Form $form ) { if ( $form->password && $form->model ()->password != $form->password ) { $form->password = bcrypt ( $form->password ); } } ); $form->saved ( function () { admin_toastr ( trans ( 'admin.update_succeeded' ) ); return redirect ( admin_base_path ( 'auth/setting' ) ); } ); } ); } /** * @return string|\Symfony\Component\Translation\TranslatorInterface */ protected function getFailedLoginMessage () { return Lang::has ( 'auth.failed' ) ? trans ( 'auth.failed' ) : '用户名或者密码不正确'; } /** * Get the post login redirect path. * * @return string */ protected function redirectPath () { if ( method_exists ( $this , 'redirectTo' ) ) { return $this->redirectTo (); } return property_exists ( $this , 'redirectTo' ) ? $this->redirectTo : config ( 'admin.route.prefix' ); } /** * Send the response after the user was authenticated. * * @param \Illuminate\Http\Request $request * * @return \Illuminate\Http\Response */ protected function sendLoginResponse ( Request $request ) { admin_toastr ( trans ( 'admin.login_successful' ) ); $request->session ()->regenerate (); return redirect ()->intended ( $this->redirectPath () ); } /** * Get the login username to be used by the controller. * * @return string */ protected function username () { return 'username'; } /** * Get the guard to be used during authentication. * * @return \Illuminate\Contracts\Auth\StatefulGuard */ protected function guard () { return Auth::guard ( 'admin' ); } }
login.blade.php视图文件
将/vendor/encore/laravel-admin/resources/view/login.blade.php复制到/resource/view中,下边是完整的html代码:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title> {{config('admin.title')}} | {{ trans('admin.login') }} </title> <!-- Tell the browser to be responsive to screen width --> <meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport"> <!-- Bootstrap 3.3.5 --> <link rel="stylesheet" href="{{ admin_asset(" /vendor/laravel-admin/AdminLTE/bootstrap/css/bootstrap.min.css ") }}"> <!-- Font Awesome --> <link rel="stylesheet" href="{{ admin_asset(" /vendor/laravel-admin/font-awesome/css/font-awesome.min.css ") }}"> <!-- Theme style --> <link rel="stylesheet" href="{{ admin_asset(" /vendor/laravel-admin/AdminLTE/dist/css/AdminLTE.min.css ") }}"> <!-- iCheck --> <link rel="stylesheet" href="{{ admin_asset(" /vendor/laravel-admin/AdminLTE/plugins/iCheck/square/blue.css ") }}"> <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries --> <!-- WARNING: Respond.js doesn't work if you view the page via file:// --> <!--[if lt IE 9]> <script src="//oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"> </script> <script src="//oss.maxcdn.com/respond/1.4.2/respond.min.js"> </script> <![endif]--> </head> <body class="hold-transition login-page" @if(config( 'admin.login_background_image'))style="background: url({{config('admin.login_background_image')}}) no-repeat;background-size: cover;" @endif> <div class="login-box"> <div class="login-logo"> <a href="{{ admin_base_path('/') }}"> <b> {{config('admin.name')}} </b> </a> </div> <!-- /.login-logo --> <div class="login-box-body"> <p class="login-box-msg"> {{ trans('admin.login') }} </p> <form action="{{ admin_base_path('auth/login') }}" method="post" id="login-form"> <div class="form-group has-feedback {!! !$errors->has('username') ?: 'has-error' !!}"> @if($errors->has('username')) @foreach($errors->get('username') as $message) <label class="control-label" for="inputError"> <i class="fa fa-times-circle-o"> </i> {{$message}} </label> </br> @endforeach @endif <input type="input" class="form-control" placeholder="{{ trans('admin.username') }}" name="username" value="{{ old('username') }}"> <span class="glyphicon glyphicon-envelope form-control-feedback"> </span> </div> <div class="form-group has-feedback {!! !$errors->has('password') ?: 'has-error' !!}"> @if($errors->has('password')) @foreach($errors->get('password') as $message) <label class="control-label" for="inputError"> <i class="fa fa-times-circle-o"> </i> {{$message}} </label> </br> @endforeach @endif <input type="password" class="form-control" placeholder="{{ trans('admin.password') }}" name="password"> <span class="glyphicon glyphicon-lock form-control-feedback"> </span> </div> <div class="form-group has-feedback {!! !$errors->has('captcha') ?: 'has-error' !!}"> @if($errors->has('captcha')) @foreach($errors->get('captcha') as $message) <label class="control-label" for="inputError"> <i class="fa fa-times-circle-o"> </i> {{$message}} </label> </br> @endforeach @endif <div id="div_geetest_lib"> <div id="div_id_embed"> </div> </div> </div> <div class="row"> <!-- /.col --> <div class="col-xs-4 col-md-offset-4"> <input type="hidden" name="_token" value="{{ csrf_token() }}"> <button type="submit" class="btn btn-primary btn-block btn-flat"> {{ trans('admin.login') }} </button> </div> <!-- /.col --> </div> </form> </div> <!-- /.login-box-body --> </div> <!-- /.login-box --> <!-- jQuery 2.1.4 --> <script src="{{ admin_asset(" /vendor/laravel-admin/AdminLTE/plugins/jQuery/jQuery-2.1.4.min.js ")}} "> </script> <!-- Bootstrap 3.3.5 --> <script src="{{ admin_asset(" /vendor/laravel-admin/AdminLTE/bootstrap/js/bootstrap.min.js ")}}"> </script> <!-- iCheck --> <script src="{{ admin_asset(" /vendor/laravel-admin/AdminLTE/plugins/iCheck/icheck.min.js ")}}"> </script> <script> $(function() { $('input').iCheck({ checkboxClass: 'icheckbox_square-blue', radioClass: 'iradio_square-blue', increaseArea: '20%' // optional }); }); </script> <script> var gtFailbackFrontInitial = function(result) { var s = document.createElement('script'); s.id = 'gt_lib'; s.src = 'http://static.geetest.com/static/js/geetest.0.0.0.js'; s.charset = 'UTF-8'; s.type = 'text/javascript'; document.getElementsByTagName('head')[0].appendChild(s); var loaded = false; s.onload = s.onreadystatechange = function() { if (!loaded && (!this.readyState || this.readyState === 'loaded' || this.readyState === 'complete')) { loadGeetest(result); loaded = true; } }; } //get geetest server status, use the failback solution var loadGeetest = function(config) { //1. use geetest capthca window.gt_captcha_obj = new window.Geetest({ gt: config.gt, challenge: config.challenge, product: 'embed', offline: !config.success }); gt_captcha_obj.appendTo("#div_id_embed"); } s = document.createElement('script'); s.src = 'http://api.geetest.com/get.php?callback=gtcallback'; $("#div_geetest_lib").append(s); var gtcallback = (function() { var status = 0, result, apiFail; return function(r) { status += 1; if (r) { result = r; setTimeout(function() { if (!window.Geetest) { apiFail = true; gtFailbackFrontInitial(result) } }, 1000) } else if (apiFail) { return } if (status == 2) { loadGeetest(result); } } })() $.ajax({ url: "/auth/start_captcha?rand=" + Math.round(Math.random() * 100), type: "get", dataType: 'JSON', success: function(result) { // console.log(result); gtcallback(result) } }) $(function() { //验证是否点击了极验证,没有点击不可以提交,并做出错误提示 $('form#login-form').submit(function() { var geetest_validate = $(this).find('input[name="geetest_validate"]').val(); if (!geetest_validate) { return false } }) }) </script> </body> </html>
添加zh-CN语言包验证提示
在/resources/lang/zh-CN中添加auth.php,代码如下:
<?php return [ /* |-------------------------------------------------------------------------- | Authentication Language Lines |-------------------------------------------------------------------------- | | The following language lines are used during authentication for various | messages that we need to display to the user. You are free to modify | these language lines according to your application's requirements. | */ //验证错误提示 'failed' => '信息不正确,验证失败', //登录失败多次提示 'throttle' => 'Too many login attempts. Please try again in :seconds seconds.', ];
总结
代码不易,思路不难,学到的点个赞,谢谢。
发表评论