Laravel-admin重写后台登录逻辑,新增字段实现第三方登录绑定功能
2020-01-09 admin laravel 1510
因需要绑定微信等第三方登录,laravel-admin原登录逻辑需要修改。查询官方文档,重写登录逻辑的方法是,在路由文件app/Admin/routes.php中,覆盖掉登录页面和登录逻辑的路由,即可实现自定义的功能:
Route::group([ 'prefix' => config('admin.prefix'), 'namespace' => Admin::controllerNamespace(), 'middleware' => ['web', 'admin'],], function (Router $router) { $router->get('auth/login', 'AuthController@getLogin'); $router->post('auth/login', 'AuthController@postLogin');});
在自定义的路由器AuthController中的getLogin、postLogin方法里分别实现自己的登录页面和登录逻辑。参考控制器文件AuthController.php,视图文件login.blade.php。搜索AuthController.php,发现已预留了扩展接口,可用来覆盖原方法:
我们实现只需要在app/Admin/Controllers/AuthController.php中,将需要修改的方法写在这,即可覆盖掉原控制器中的方法,实现自定义,路由无需修改。
namespace App\Admin\Controllers; use Encore\Admin\Controllers\AuthController as BaseAuthController; class AuthController extends BaseAuthController { }
原控制器中的代码如下,可参照修改:
namespace Encore\Admin\Controllers; 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\Lang; use Illuminate\Support\Facades\Redirect; use Illuminate\Support\Facades\Validator; class AuthController extends Controller { /** * @var string */ protected $loginView = 'admin::login'; /** * Show the login page. * * @return \Illuminate\Contracts\View\Factory|Redirect|\Illuminate\View\View */ public function getLogin() { if ($this->guard()->check()) { return redirect($this->redirectPath()); } return view($this->loginView); } /** * Handle a login request. * * @param Request $request * * @return mixed */ public function postLogin(Request $request) { $this->loginValidator($request->all())->validate(); $credentials = $request->only([$this->username(), 'password']); $remember = $request->get('remember', false); if ($this->guard()->attempt($credentials, $remember)) { return $this->sendLoginResponse($request); } return back()->withInput()->withErrors([ $this->username() => $this->getFailedLoginMessage(), ]); } /** * Get a validator for an incoming login request. * * @param array $data * * @return \Illuminate\Contracts\Validation\Validator */ protected function loginValidator(array $data) { return Validator::make($data, [ $this->username() => 'required', 'password' => 'required', ]); } /** * User logout. * * @return Redirect */ public function getLogout(Request $request) { $this->guard()->logout(); $request->session()->invalidate(); return redirect(config('admin.route.prefix')); } /** * User setting page. * * @param Content $content * * @return Content */ public function getSetting(Content $content) { $form = $this->settingForm(); $form->tools( function (Form\Tools $tools) { $tools->disableList(); $tools->disableDelete(); $tools->disableView(); } ); return $content ->title(trans('admin.user_setting')) ->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() { $class = config('admin.database.users_model'); $form = new Form(new $class()); $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_url('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_url('auth/setting')); }); return $form; } /** * @return string|\Symfony\Component\Translation\TranslatorInterface */ protected function getFailedLoginMessage() { return Lang::has('auth.failed') ? trans('auth.failed') : 'These credentials do not match our records.'; } /** * 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 Admin::guard(); } }
实现第三方登录,已有成熟的组件,安装即可。如果添加了字段,表结构变化 了,需要修改一下config/admin.php里面的auth.providers.model为你的新模型,然后用你写的控制器就好了,不需要去重新定义provider和driver.
'model' => Encore\Admin\Auth\Database\Administrator::class,
原模型在vendor/encore/laravel-admin/src/Auth/Database/Administrator.php,代码如下:
namespace Encore\Admin\Auth\Database; use Encore\Admin\Traits\AdminBuilder; use Illuminate\Auth\Authenticatable; use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Support\Facades\Storage; /** * Class Administrator. * * @property Role[] $roles */ class Administrator extends Model implements AuthenticatableContract { use Authenticatable, AdminBuilder, HasPermissions; protected $fillable = ['username', 'password', 'name', 'avatar']; /** * Create a new Eloquent model instance. * * @param array $attributes */ public function __construct(array $attributes = []) { $connection = config('admin.database.connection') ?: config('database.default'); $this->setConnection($connection); $this->setTable(config('admin.database.users_table')); parent::__construct($attributes); } /** * Get avatar attribute. * * @param string $avatar * * @return string */ public function getAvatarAttribute($avatar) { if (url()->isValidUrl($avatar)) { return $avatar; } $disk = config('admin.upload.disk'); if ($avatar && array_key_exists($disk, config('filesystems.disks'))) { return Storage::disk(config('admin.upload.disk'))->url($avatar); } $default = config('admin.default_avatar') ?: '/vendor/laravel-admin/AdminLTE/dist/img/user2-160x160.jpg'; return admin_asset($default); } /** * A user has and belongs to many roles. * * @return BelongsToMany */ public function roles() : BelongsToMany { $pivotTable = config('admin.database.role_users_table'); $relatedModel = config('admin.database.roles_model'); return $this->belongsToMany($relatedModel, $pivotTable, 'user_id', 'role_id'); } /** * A User has and belongs to many permissions. * * @return BelongsToMany */ public function permissions() : BelongsToMany { $pivotTable = config('admin.database.user_permissions_table'); $relatedModel = config('admin.database.permissions_model'); return $this->belongsToMany($relatedModel, $pivotTable, 'user_id', 'permission_id'); } }
改了字段,这个数据库对应配置的model要修改。下面,以微信登录为例,控制器的app/Admin/Controllers代码如下:
namespace App\Admin\Controllers; use App\Models\AdminUserModel; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Hash; use Laravel\Socialite\Facades\Socialite; use Illuminate\Support\Str; use Overtrue\EasySms\EasySms;//短信 use Encore\Admin\Controllers\AuthController as BaseAuthController; class AuthController extends BaseAuthController { //重写登录 protected $loginView = 'auth.adminlogin'; public function getLogin() { if ($this->guard()->check()) { return redirect($this->redirectPath()); } return view($this->loginView); } public function postLogin(Request $request) { //用户名密码登录 $this->loginValidator($request->all())->validate(); $credentials = $request->only([$this->username(), 'password']); $remember = $request->get('remember', false); if ($this->guard()->attempt($credentials, $remember)) { return $this->sendLoginResponse($request); } return back()->withInput()->withErrors([ $this->username() => $this->getFailedLoginMessage(), ]); } //微信一键登录,静默方式获取openid public function weixin(Request $request){ $appid = env('WEIXIN_KEY'); $appKey = env('WEIXIN_SECRET'); //通过code获得openid if (!isset($request->code)){ //触发微信返回code码 $scheme = $_SERVER['HTTPS']=='on' ? 'https://' : 'http://'; $uri = $_SERVER['PHP_SELF'].$_SERVER['QUERY_STRING']; if($_SERVER['REQUEST_URI']) $uri = $_SERVER['REQUEST_URI']; $baseUrl = urlencode($scheme.$_SERVER['HTTP_HOST'].$uri); $urlObj["appid"] = $appid; $urlObj["redirect_uri"] = "$baseUrl"; $urlObj["response_type"] = "code"; $urlObj["scope"] = "snsapi_base"; $urlObj["state"] = "STATE"."#wechat_redirect"; $buff = ""; foreach ($urlObj as $k => $v){ if($k != "sign") $buff .= $k . "=" . $v . "&"; } $bizString = trim($buff, "&"); $url = "https://open.weixin.qq.com/connect/oauth2/authorize?".$bizString; Header("Location: $url"); exit(); }else{ //获取code码,以获取openid $code = $request->code; $urlObj["appid"] = $appid; $urlObj["secret"] = $appKey; $urlObj["code"] = $code; $urlObj["grant_type"] = "authorization_code"; $buff = ""; foreach ($urlObj as $k => $v){ if($k != "sign") $buff .= $k . "=" . $v . "&"; } $bizString = trim($buff, "&"); $url = "https://api.weixin.qq.com/sns/oauth2/access_token?".$bizString; $options = array(); $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_TIMEOUT, 30); if (!empty($options)) { curl_setopt_array($ch, $options); } //https请求 不验证证书和host curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); $res = curl_exec($ch); curl_close($ch); //取出openid $data = json_decode($res,true); $openid = $data['openid']; //查找数据库中是否有该openid $check = AdminUserModel::where('openid', $openid)->first(); if (!$check) {//如果第一次访问,跳转到绑定账号页面 $bd = url("/admin/bdyyzh?timestamp=".time()."&openid=".$openid); return redirect($bd); } else { //登录 $login['username'] = $check->username; $login['password'] = $check->password; if ($this->guard()->login($check)) { admin_toastr(trans('admin.login_successful')); $request->session()->regenerate(); return redirect()->intended($this->redirectPath()); }else{ session()->flash('danger', '登录失败!'); return redirect()->back()->withInput(); } } } } //绑定已有账号 public function bdyyzh(Request $request){ if(isset($request->qqid)){ $qqid = $request->qqid; return view('auth/adminbduser',compact('qqid')); }elseif(isset($request->openid)){ $openid = $request->openid; return view('auth/adminbduser',compact('openid')); }elseif(isset($request->phone)){ $phone = $request->phone; return view('auth/adminbduser',compact('phone')); } //session()->flash('success', 'QQ登录成功!'); //return redirect()->route('cxsy'); } //查询账号密码,如账号密码正确则更新qqid或openid或phone public function cxbd(Request $request){ //dd($request->all()); $this->loginValidator($request->all())->validate(); $credentials = $request->only([$this->username(), 'password']); $remember = $request->get('remember', false); if ($this->guard()->attempt($credentials, $remember)) { //验证通过 if(isset($request->qqid)){ $qqid = $request->qqid; AdminUserModel::where('username', $request->username)->update(['qqid' => $qqid]); }elseif(isset($request->openid)){ $openid = $request->openid; AdminUserModel::where('username', $request->username)->update(['openid' => $openid]); }elseif(isset($request->phone)){ $phone = $request->phone; AdminUserModel::where('username', $request->username)->update(['phone' => $phone]); } //保存session并跳转到后台 return $this->sendLoginResponse($request); }else{ session()->flash('danger', '很抱歉,您的用户名和密码不匹配!'); return redirect()->back()->withInput(); } } }
前端文件就省略了。