上边完成了基本布局,发现某些 js,css缺失。这个时候,需要补进来。然后,完成服务端的注册登录逻辑,以及 gee 验证。
修补
加入以下文件
static/style/css/nprogress.css
static/style/css/nprogress.min.css
static/style/js/fn.js
static/style/js/gt.js
static/style/js/nprogress.min.js
部分调整
- 将 nprogress.min.js 和 app.js 的加载顺序更换一下。因为 app.js 中会使用到 nprogress 的封装
git add .
git commit -m '修复引入js,css不存在的bug'
认证脚手架
php artisan ui:auth
# 因为之前已经有了 layouts 相关的文件,这个时候会提示是否要覆盖,输入 no 回车。这个时候,会补入和修改相关的文件
# 查看变更的文件
git status
# 删掉其他新增文件,只保留 resources/views/auth/ 下的文件
# web.php 路由也处理一下。之前就已经好了,这次注入是重复的,可以删掉重复的部分。
做好上边这些,然后开始修改 user 表的迁移文件,以及将 User模型移动到 app\Models\
下。
迁移文件
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUsersTable extends Migration
{
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('wxweb_openid', 64)->unique()->nullable(); // 微信公众号openid
$table->string('wxapp_openid', 64)->unique()->nullable(); // 微信小程序openid
$table->string('wxapp_session_key', 64)->nullable(); // 微信小程序 session_key
$table->string('wx_unionid', 64)->unique()->nullable(); // 微信开放平台唯一id
$table->string('bd_openid', 64)->unique()->nullable(); // 百度小程序openid
$table->string('bd_unionid', 64)->unique()->nullable(); // 百度开放平台唯一id
$table->string('bd_session_key', 64)->nullable(); // 小程序 session_key
$table->string('account', 16)->nullable()->unique();
$table->string('password')->nullable();
$table->unsignedInteger('viewid')->unique();
$table->string('nickname', 64)->nullable();
$table->string('username', 64)->nullable();
$table->string('phone_prefix', 8)->default('86')->comment('手机号码前缀');
$table->string('phone', 16)->nullable();
$table->unique(['phone_prefix', 'phone']);
$table->smallInteger('gender')->default(1)->comment('性别,0 未知,1男,2女');
// 普通索引 (index)
$table->string('email', 32)->nullable()->index('email');
$table->string('qq', 16)->nullable()->comment('qq');
$table->string('wechat', 32)->nullable()->comment('微信');
$table->date('birthday')->nullable()->comment('生日');
$table->string('avatar', 200)->default('storage/upload/image/avatar/default.jpg')->comment('头像');
$table->unsignedMediumInteger('province')->nullable();
$table->unsignedMediumInteger('city')->nullable();
$table->unsignedMediumInteger('area')->nullable();
$table->string('address')->nullable();
$table->point('position')->nullable();
$table->string('signature', 255)->default('美的事物是永恒的喜悦!')->nullable()->comment('签名');
$table->unsignedTinyInteger('referer')->default(1)->comment('注册来源 1 微信小程序 2 百度小程序 3 官方网站');
$table->bigInteger('register_ip')->default(0)->comment('注册时ip');
$table->unsignedInteger('online_days')->default(0);
$table->string('verification_token')->nullable();
$table->rememberToken();
$table->dateTime('last_login_at')->nullable();
$table->timestamp('email_verified_at')->nullable();
$table->nullableTimestamps();
});
}
public function down()
{
Schema::dropIfExists('users');
}
}
模型文件
- 新建文件夹
app/Models/
- 将 app 下的 User.php 移动到 app/Models 下。
- 修改命名空间以及白名单。如下。
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
use Notifiable;
protected $fillable = [
'wxweb_openid', 'wxapp_openid', 'wxapp_session_key', 'wx_unionid', 'bd_openid', 'bd_unionid', 'bd_session_key',
'account', 'password', 'viewid', 'nickname', 'username', 'phone_prefix', 'phone', 'gender', 'email', 'qq', 'wechat',
'birthday', 'avatar', 'province', 'city', 'area', 'address', 'position', 'signature', 'referer', 'register_ip',
'online_days', 'last_login_at'];
protected $hidden = [
'password', 'remember_token',
];
protected $casts = [
'email_verified_at' => 'datetime',
];
}
然后,先提交代码。
git add .
git commit -m '新增Models文件夹,用来安放模型,修改user迁移文件'
再替换 User 的命名空间,全局搜索 App\User
,换成 App\Models\User
修改注册登录等页面
# login.blade.php
@extends('layouts.app')
@section('title')
个人登录
@endsection
@section('style')
<style>
.login-page {
display: flex;
align-items: center;
width: 100%;
height: 100%;
background: url({{asset('static/image/common/reg-login-bg.jpg')}});
background-size: cover;
}
.login-page .container-fluid {
display: flex;
justify-content: center;
padding-left: 0;
padding-right: 0;
}
.login-page .card-panel {
display: inline-block;
width: 100%;
max-width: 720px;
}
.login-page .card-header {
text-align: center;
font-size: 20px;
}
.login-page .col-form-label {
font-weight: 600;
}
/* 小分辨率处理 */
@media (max-width: 720px)
{
.login-page {
background: #fff;
align-items: flex-start;
}
.login-page .logo {
align-self: center;
width: 80px;
height: 80px;
background: url({{asset('static/image/common/logo.png')}});
background-size: 80px 80px;
}
.card {
border: none;
border-radius: 0;
margin-top: 60px;
}
.card-header {
display: none;
}
}
</style>
@endsection
@section('content')
<div class="container-fluid">
<div class="card-panel">
<div class="card">
<div class="card-header">个人登录</div>
<div class="logo"></div>
<div class="card-body">
<form method="POST" action="{{ route('login') }}" aria-label="个人登录">
@csrf
<div class="form-group row">
<label for="account" class="col-md-4 col-form-label text-md-right">账号</label>
<div class="col-md-5">
<input id="account" type="text" class="form-control{{ $errors->has('account') ? ' is-invalid' : '' }}" name="account" value="{{ old('account') }}" required autofocus>
@if ($errors->has('account'))
<span class="invalid-feedback" role="alert">
<strong>{{ $errors->first('account') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group row">
<label for="password" class="col-md-4 col-form-label text-md-right">密码</label>
<div class="col-md-5">
<input id="password" type="password" class="form-control{{ $errors->has('password') ? ' is-invalid' : '' }}" name="password" required>
@if ($errors->has('password'))
<span class="invalid-feedback" role="alert">
<strong>{{ $errors->first('password') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group row">
<div class="col-md-6 offset-md-4">
<div class="checkbox">
<label>
<input type="checkbox" name="remember" id="remember" checked style="margin-right: 6px;">记住密码
</label>
</div>
</div>
</div>
<div class="form-group row mb-0">
<div class="col-md-8 offset-md-4">
<button type="submit" class="btn btn-primary">登录</button>
<a class="btn btn-link" href="{{ route('password.request') }}">忘记密码</a>
</div>
</div>
<div class="form-group row" style="margin-top:40px;justify-content: center;font-size: 14px;color:#333;">
<span>如果没有账号,请<span><a style="margin:0 5px;" href="{{route('register')}}">注册</a>
<span style="font-size: 16px;">或第三方登录</span>
</div>
</form>
</div>
</div>
</div>
</div>
@endsection
再
# register.blade.php
@extends('layouts.app')
@section('title')
个人登录
@endsection
@section('style')
<style>
.register-page {
display: flex;
align-items: center;
width: 100%;
height: 100%;
background: url({{asset('static/image/common/reg-login-bg.jpg')}});
background-size: cover;
}
.register-page .container-fluid {
display: flex;
justify-content: center;
padding-left: 0;
padding-right: 0;
}
.register-page .card-panel {
display: inline-block;
width: 100%;
max-width: 720px;
}
.register-page .card-header {
text-align: center;
font-size: 20px;
}
.register-page .col-form-label {
font-weight: 600;
}
/* 小分辨率处理 */
@media (max-width: 720px)
{
.register-page {
background: #fff;
align-items: flex-start;
}
.register-page .logo {
align-self: center;
width: 80px;
height: 80px;
background: url({{asset('static/image/common/logo.png')}});
background-size: 80px 80px;
}
.card {
border: none;
border-radius: 0;
margin-top: 60px;
}
.card-header {
display: none;
}
}
/*验证码相关*/
/*去掉logo广告*/
#embed-captcha{
width: 100%;
}
#embed-captcha .geetest_logo, .geetest_success_logo, .geetest_wait{
display: none;
}
.hide{display:none;}
/*最小宽度*/
.geetest_holder.geetest_wind {
min-width: 220px;
}
.geetest_copyright{
display: none;
}
/*圆圈圈*/
#embed-captcha .geetest_radar{
width: 24px;
height: 24px;
margin: 5px 6px;
}
#embed-captcha .geetest_btn, #embed-captcha .geetest_radar_tip, #embed-captcha .geetest_success_radar_tip, #embed-captcha span{
height: 36px;
line-height: 36px;
}
.geetest_holder.geetest_wind .geetest_radar_tip, .geetest_holder.geetest_wind .geetest_success_radar_tip
{
height: 36px;
line-height: 36px;
}
.geetest_popup_ghost{
display: none;
}
/*成功图标*/
#embed-captcha .geetest_success_box
{
top:6px;
}
</style>
@endsection
@section('content')
<div class="container-fluid">
<div class="card-panel">
<div class="card">
<div class="card-header">个人注册</div>
<div class="logo"></div>
<div class="card-body">
<form method="POST" action="{{ route('register') }}" aria-label="{{ __('Register') }}">
@csrf
<div class="form-group row">
<label for="account" class="col-md-4 col-form-label text-md-right">账号</label>
<div class="col-md-5">
<input placeholder="请输入手机号" id="account" type="text" class="form-control{{ $errors->has('account') ? ' is-invalid' : '' }}" name="account" value="{{ old('account') }}" required autofocus>
@if ($errors->has('account'))
<span class="invalid-feedback" role="alert">
<strong>{{ $errors->first('account') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group row">
<label for="password" class="col-md-4 col-form-label text-md-right">密码</label>
<div class="col-md-5">
<input placeholder="6-16位密码,区分大小写" id="password" type="password" class="form-control{{ $errors->has('password') ? ' is-invalid' : '' }}" name="password" required>
@if ($errors->has('password'))
<span class="invalid-feedback" role="alert">
<strong>{{ $errors->first('password') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group row">
<label for="password_confirmation" class="col-md-4 col-form-label text-md-right">确认密码</label>
<div class="col-md-5">
<input placeholder="再次确认密码" id="password_confirmation" type="password" class="form-control" name="password_confirmation" required>
@if ($errors->has('password_confirmation'))
<span class="invalid-feedback" role="alert">
<strong>{{ $errors->first('password_confirmation') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group row">
<label for="email" class="col-md-4 col-form-label text-md-right">邮箱</label>
<div class="col-md-5">
<input placeholder="请输入邮箱" id="email" type="email" class="form-control{{ $errors->has('email') ? ' is-invalid' : '' }}" name="email" required>
@if ($errors->has('email'))
<span class="invalid-feedback" role="alert">
<strong>{{ $errors->first('email') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group row">
<div class= "col-md-5 offset-md-4">
<div id="embed-captcha"></div>
<p id="wait" class="show">正在加载验证码......</p>
<p id="notice" class="hide">请先完成验证</p>
@if ($errors->has('geetest_validate'))
<span class="help-block geetest-help" style="color:#a94442;">
<strong>{{ $errors->first('geetest_validate') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group row">
<div class="col-md-5 offset-md-4">
同意并接受 <a href="javascript:void(0)">《服务条款》</a>
</div>
</div>
<div class="form-group row mb-0">
<div class="col-md-5 offset-md-4">
<button type="submit" class="btn btn-primary btn-block">注册</button>
</div>
</div>
<div class="form-group row" style="margin-top:40px;justify-content: center;font-size: 14px;color:#333;">
<span>如果拥有账号,请直接<span><a style="margin:0 5px;" href="{{route('login')}}">登录</a>
<span style="font-size: 16px;">或第三方登录</span>
</div>
</form>
</div>
</div>
</div>
</div>
@endsection
@section('script')
<script src="{{ asset('static/style/js/gt.js') }}"></script>
<script>
// 验证码
var geeInit = function(){
var captcha = $('#embed-captcha');
if(!captcha)
return;
$.ajax({
url: "{{route('start_gee')}}",
type: "get",
dataType: "json",
success:function(data){
if(data.code == 0)
{
setGee(data.data);
}
}
});
}
var setGee = function(data){
try{
data = JSON.parse(data);
initGeetest({
width: "100%",
gt: data.gt,
protocol:"https://",
challenge: data.challenge,
new_captcha: data.new_captcha,
product: "custom",
area:"#embed-captcha",
next_width:"70%",
offline: !data.success
}, handlerEmbed);
}
catch(e)
{
}
}
var handlerEmbed = function (captchaObj) {
window.captchaObj = captchaObj;
captchaObj.appendTo("#embed-captcha");
captchaObj.onReady(function () {
$("#wait")[0].className = "hide";
setTimeout(function(){
// $(".geetest_holder.geetest_wind").css("min-width", 220);
$(".geetest_holder.geetest_wind").css("height", 36);
// $(".geetest_holder.geetest_wind").css("width", 220);
}, 1 * 100);
});
captchaObj.onSuccess(function(){
var result = captchaObj.getValidate();
if(result)
{
$('.form-register').append('<input type="hidden" name="geetest_challenge" value="' + result.geetest_challenge + '" />');
$('.form-register').append('<input type="hidden" name="geetest_validate" value="' + result.geetest_validate + '" />');
$('.form-register').append('<input type="hidden" name="geetest_seccode" value="' + result.geetest_seccode + '" />');
if($('.geetest-help').length > 0)
{
$('.geetest-help').remove();
}
}
});
};
$(document).ready(function(){
geeInit();
});
</script>
@endsection
再
# verify.blade.php
@extends('layouts.app')
@section('title')
邮箱验证
@endsection
@section('style')
<style>
.verification-notice-page {
margin-top: 30px;
}
</style>
@endsection
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">{{ __('Verify Your Email Address') }}</div>
<div class="card-body">
@if (session('resent'))
<div class="alert alert-success" role="alert">
{{ __('A fresh verification link has been sent to your email address.') }}
</div>
@endif
{{ __('Before proceeding, please check your email for a verification link.') }}
{{ __('If you did not receive the email') }}, <a href="{{ route('verification.resend') }}">{{ __('click here to request another') }}</a>.
</div>
</div>
</div>
</div>
</div>
@endsection
再
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">{{ __('Reset Password') }}</div>
<div class="card-body">
<form method="POST" action="{{ route('password.update') }}">
@csrf
<input type="hidden" name="token" value="{{ $token }}">
<div class="form-group row">
<label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>
<div class="col-md-6">
<input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ $email ?? old('email') }}" required autocomplete="email" autofocus>
@error('email')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="form-group row">
<label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>
<div class="col-md-6">
<input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="new-password">
@error('password')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="form-group row">
<label for="password-confirm" class="col-md-4 col-form-label text-md-right">{{ __('Confirm Password') }}</label>
<div class="col-md-6">
<input id="password-confirm" type="password" class="form-control" name="password_confirmation" required autocomplete="new-password">
</div>
</div>
<div class="form-group row mb-0">
<div class="col-md-6 offset-md-4">
<button type="submit" class="btn btn-primary">
{{ __('Reset Password') }}
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">{{ __('Reset Password') }}</div>
<div class="card-body">
<form method="POST" action="{{ route('password.update') }}">
@csrf
<input type="hidden" name="token" value="{{ $token }}">
<div class="form-group row">
<label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>
<div class="col-md-6">
<input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ $email ?? old('email') }}" required autocomplete="email" autofocus>
@error('email')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="form-group row">
<label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>
<div class="col-md-6">
<input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="new-password">
@error('password')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="form-group row">
<label for="password-confirm" class="col-md-4 col-form-label text-md-right">{{ __('Confirm Password') }}</label>
<div class="col-md-6">
<input id="password-confirm" type="password" class="form-control" name="password_confirmation" required autocomplete="new-password">
</div>
</div>
<div class="form-group row mb-0">
<div class="col-md-6 offset-md-4">
<button type="submit" class="btn btn-primary">
{{ __('Reset Password') }}
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection
在 RegisterController.php
中,我没要重写 register 方法,还有对 create 和 validator 方法进行修改,以满足自己的需要。顺便,用到了 gee 验证,在这里还有将其相关的逻辑 trait 进来。
**完整版的RegisterController **
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use App\Models\User;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Illuminate\Auth\Events\Registered;
use Illuminate\Http\Request;
use App\Traits\GeetestTraits;
class RegisterController extends Controller
{
/*
|--------------------------------------------------------------------------
| Register Controller
|--------------------------------------------------------------------------
|
| This controller handles the registration of new users as well as their
| validation and creation. By default this controller uses a trait to
| provide this functionality without requiring any additional code.
|
*/
use RegistersUsers;
use GeetestTraits;
/**
* Where to redirect users after registration.
*
* @var string
*/
protected $redirectTo = RouteServiceProvider::HOME;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest');
}
public function register(Request $request)
{
$this->geetest($request);
$this->validator($request->all())->validate();
$data = $request->all();
$data['ip'] = ip2long($request->getClientIP());
event(new Registered($user = $this->create($data)));
$this->guard()->login($user);
return $this->registered($request, $user)
?: redirect($this->redirectPath());
}
/**
* Get a validator for an incoming registration request.
*
* @param array $data
* @return \Illuminate\Contracts\Validation\Validator
*/
protected function validator(array $data)
{
return Validator::make($data, [
'account' => 'required|string|max:16|regex:/^(1[3-9])\\d{9}$/i|unique:users',
'password' => 'required|confirmed|min:6',
'password_confirmation' => 'required|same:password',
'email' => 'required|email|max:255',
],[],[
'account' => '账号',
'password' => '密码',
'password_confirmation' => '确认密码',
'email' => '邮箱'
]);
}
/**
* Create a new user instance after a valid registration.
*
* @param array $data
* @return \App\User
*/
protected function create(array $data)
{
$user = User::where('phone', $data['account'])->first();
if ($user) {
return back()->with(['error' => '手机号码已注册,请使用微信小程序设置密码']);
}
$fill = [
'account' => $data['account'],
'password' => Hash::make($data['password']),
'phone' => $data['account'],
'email' => $data['email'],
'register_ip' => $data['ip'],
'signature' => $this->randomSignature()
];
$user = User::create($fill);
return User::where('id', $user->id)->first();
}
private function randomSignature()
{
$words = [
'烟花飞腾的时候,火焰掉入海中。遗忘就和记得一样,是送给彼此最好的纪念。爱从来都不是归宿,也不是彼此最好的救赎。',
'仿佛有痛楚。如果我晕眩。那是因为幻觉丰盛,能量薄弱。足以支持我对你的迷恋,不过支持我们的快乐。',
'天没有边,没有界。心是花园也是荒野。光阴在花绽开中消亡,歌舞却永不停下。将一片云纱与你。敢不敢,愿不愿,一起飞越长空。',
'一道电光劈开天幕。苍穹间有笔疾书,叫做战胜脆弱。',
'虚幻之物对应着冥冥之路。',
'美的事物是永恒的喜悦。',
'舞低杨柳楼心月,歌尽桃花扇底风。从别后,忆相逢,几回魂梦与君同。',
'车如流水马如龙,花月正春风。',
'闲引鸳鸯香径里,手挼红杏蕊。',
'夏雨雪,天地合,乃敢与君绝。',
'一百年前,你不是你,我不是我。眼泪是真的,悲哀是假的。本来没因果。一百年后,没有你,也没有我。'
];
$index = array_rand($words, 1);
return $words[$index];
}
}
完整版的GeetestTraits
<?php
namespace App\Traits;
use Illuminate\Support\Facades\Validator;
use Illuminate\Http\Request;
use App\Utils\Geetest;
use Session;
trait GeetestTraits{
public function geetest(Request $request)
{
$this->__validGeetestData($request->all(), '请先完成验证!');
$geetest_challenge = $request->input('geetest_challenge');
$geetest_validate = $request->input('geetest_validate');
$geetest_seccode = $request->input('geetest_seccode');
$geetest = app(Geetest::class);
// 二次验证
$gtserver = Session::get('gtserver');
if($gtserver == 1)
{
$data = array(
"user_id" => 'yueqiubao',
"client_type" => "web",
"ip_address" => $request->getClientIp()
);
$result = $geetest->success_validate($geetest_challenge, $geetest_validate, $geetest_seccode, $data);
if($result == FALSE)
$this->__validGeetestData(array(), '二次验证不通过!');
}
else
{
$result = $geetest->fail_validate($geetest_challenge, $geetest_validate, $geetest_seccode);
if($result == FALSE)
$this->__validGeetestData(array(), '宕机,二次验证不通过!');
}
}
/**
* 验证geetest
*
* @param array $data
* @return \Illuminate\Contracts\Validation\Validator
*/
private function __validGeetestData($data, $message)
{
return Validator::make($data, [
'geetest_validate' => 'required',
], [
'geetest_validate.required' => $message,
])->validate();
}
// 获取geetst验证码信息。默认array其实会转成json输出。
public function start_gee(Request $request, Geetest $geetest)
{
$data = array(
"user_id" => 'yueqiubao',
"client_type" => "web",
"ip_address" => $request->getClientIp(),
);
$status = $geetest->pre_process($data, 1);
$request->session()->put('gtserver', $status);
$request->session()->put('user_id', $data['user_id']);
return response()->json(array('code' => 0, 'data' => $geetest->get_response_str()));
}
}
完整版的 Geetest
<?php
namespace App\Utils;
define("CAPTCHA_ID", "xxxxxxxxx");
define("PRIVATE_KEY", "xxxxxxxx");
class Geetest
{
const GT_SDK_VERSION = 'php_3.0.0';
public static $connectTimeout = 1;
public static $socketTimeout = 1;
private $response;
public function __construct()
{
$this->captcha_id = CAPTCHA_ID;
$this->private_key = PRIVATE_KEY;
}
/**
* 判断极验服务器是否down机
*
* @param array $data
* @return int
*/
public function pre_process($param, $new_captcha=1)
{
$data = array('gt'=>$this->captcha_id,
'new_captcha'=>$new_captcha
);
$data = array_merge($data,$param);
$query = http_build_query($data);
$url = "http://api.geetest.com/register.php?" . $query;
$challenge = $this->send_request($url);
if (strlen($challenge) != 32) {
$this->failback_process();
return 0;
}
$this->success_process($challenge);
return 1;
}
/**
* @param $challenge
*/
private function success_process($challenge) {
$challenge = md5($challenge . $this->private_key);
$result = array(
'success' => 1,
'gt' => $this->captcha_id,
'challenge' => $challenge,
'new_captcha'=>1
);
$this->response = $result;
}
/**
*
*/
private function failback_process() {
$rnd1 = md5(rand(0, 100));
$rnd2 = md5(rand(0, 100));
$challenge = $rnd1 . substr($rnd2, 0, 2);
$result = array(
'success' => 0,
'gt' => $this->captcha_id,
'challenge' => $challenge,
'new_captcha'=>1
);
$this->response = $result;
}
/**
* @return mixed
*/
public function get_response_str() {
return json_encode($this->response);
}
/**
* 返回数组方便扩展
*
* @return mixed
*/
public function get_response() {
return $this->response;
}
/**
* 正常模式获取验证结果
*
* @param string $challenge
* @param string $validate
* @param string $seccode
* @param array $param
* @return int
*/
public function success_validate($challenge, $validate, $seccode,$param, $json_format=1) {
if (!$this->check_validate($challenge, $validate)) {
return 0;
}
$query = array(
"seccode" => $seccode,
"timestamp"=>time(),
"challenge"=>$challenge,
"captchaid"=>$this->captcha_id,
"json_format"=>$json_format,
"sdk" => self::GT_SDK_VERSION
);
$query = array_merge($query,$param);
$url = "http://api.geetest.com/validate.php";
$codevalidate = $this->post_request($url, $query);
$obj = json_decode($codevalidate,true);
if ($obj === false){
return 0;
}
if ($obj['seccode'] == md5($seccode)) {
return 1;
} else {
return 0;
}
}
/**
* 宕机模式获取验证结果
*
* @param $challenge
* @param $validate
* @param $seccode
* @return int
*/
public function fail_validate($challenge, $validate, $seccode) {
if(md5($challenge) == $validate){
return 1;
}else{
return 0;
}
}
/**
* @param $challenge
* @param $validate
* @return bool
*/
private function check_validate($challenge, $validate) {
if (strlen($validate) != 32) {
return false;
}
if (md5($this->private_key . 'geetest' . $challenge) != $validate) {
return false;
}
return true;
}
/**
* GET 请求
*
* @param $url
* @return mixed|string
*/
private function send_request($url) {
if (function_exists('curl_exec')) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, self::$connectTimeout);
curl_setopt($ch, CURLOPT_TIMEOUT, self::$socketTimeout);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$curl_errno = curl_errno($ch);
$data = curl_exec($ch);
curl_close($ch);
if ($curl_errno >0) {
return 0;
}else{
return $data;
}
} else {
$opts = array(
'http' => array(
'method' => "GET",
'timeout' => self::$connectTimeout + self::$socketTimeout,
)
);
$context = stream_context_create($opts);
$data = @file_get_contents($url, false, $context);
if($data){
return $data;
}else{
return 0;
}
}
}
/**
*
* @param $url
* @param array $postdata
* @return mixed|string
*/
private function post_request($url, $postdata = '') {
if (!$postdata) {
return false;
}
$data = http_build_query($postdata);
if (function_exists('curl_exec')) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, self::$connectTimeout);
curl_setopt($ch, CURLOPT_TIMEOUT, self::$socketTimeout);
//不可能执行到的代码
if (!$postdata) {
curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
} else {
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
}
$data = curl_exec($ch);
if (curl_errno($ch)) {
$err = sprintf("curl[%s] error[%s]", $url, curl_errno($ch) . ':' . curl_error($ch));
$this->triggerError($err);
}
curl_close($ch);
} else {
if ($postdata) {
$opts = array(
'http' => array(
'method' => 'POST',
'header' => "Content-type: application/x-www-form-urlencoded\r\n" . "Content-Length: " . strlen($data) . "\r\n",
'content' => $data,
'timeout' => self::$connectTimeout + self::$socketTimeout
)
);
$context = stream_context_create($opts);
$data = file_get_contents($url, false, $context);
}
}
return $data;
}
/**
* @param $err
*/
private function triggerError($err) {
trigger_error($err);
}
}
?>
注册好了,再来看登录。登录中需要重写 username 方法,默认是 email,这里换成你自己需要的。项目里是 account 字段,所以在 LoginController.php 中增加方法。
/**
* Get the login username to be used by the controller.
* 登录对应的字段名
*
* @return string
*/
public function username()
{
return 'account';
}
上边这些都做好了,那么我们开始执行迁移文件。进行真正的注册登录。
先测试登录,输入账号密码,发现提示是英文的。这是语言包的问题。可以使用 https://github.com/overtrue/laravel-lang
composer require "overtrue/laravel-lang:~3.0"
# 将 config/app.php 中的 Illuminate\Translation\TranslationServiceProvider::class, 换成 Overtrue\LaravelLang\TranslationServiceProvider::class,
# 再执行下边的命令
php artisan lang:publish zh-CN
# 最后将 config/app.php 中的 locale 的值设置成 zh-CN,顺带将时区也一起改了。将 timezone 的值设置成 Asia/Shanghai
再执行登录,提示用户名和密码错误,这样就对了。然后注册一个,退出再登录。资料都填好后,注册发现报错,说 viewid 不能为空。因为注册的时候,根本没给 viewid 对应的值。
在 User::create 创建的时候,给其填充 viewid 就可以了。我没修改 User 模型,加入下边的代码。
protected static function boot()
{
parent::boot();
// 监听模型创建事件,在写入数据库之前触发
static::creating(function ($model) {
// 如果模型的 viewid 字段为空
if (!$model->viewid) {
// 调用 build_viewid 来生成 view id
$model->viewid = static::build_viewid();
}
if (!$model->nickname) {
$model->nickname = '小伙伴-' . $model->viewid;
}
});
}
public static function build_viewid()
{
$prefix = rand(1, 9);
$prefix *= 10000000;
$difference = rand(1, 9999999);
$viewid = $prefix + $difference;
if ($viewid > 99999999)
{
static::build_viewid();
}
if (!static::query()->where('viewid', $viewid)->exists()) {
return $viewid;
}
static::build_viewid();
}
再注册,发现已经成功了。但是出现了 404 页面,因为不存在 /home 这个路由的呀。那是因为注册成功后跳转到这个路由了,而这个路由的定义在 App\Providers\RouteServiceProvider 中,只需要全局将 /home 换成 / 就可以了。
到了最后,还是有问题。发现 user.show user.edit 路由不存在。因此,要加入这些路由,要创建控制器,并加入方法。
php artisan make:controller Web/UserController
# 在 UserController 中加入方法。先占着坑。
public function index($id)
{
return $id;
}
public function edit($id)
{
return $id;
}
# 在路由中加入
Route::get('/users/{user}', 'UserController@index')->name('users.show');
Route::group(['middleware' => 'auth'], function() {
Route::get('/users/{user}/edit', 'UserController@edit')->name('users.edit');
});
路由弄好了,还是报错。说 getAllPermissions 方法不存在。这个的确不存在。这个后边会处理,先将 _header.blade.php 中这个注释掉。然后,刷新就好了。再退出,试试登录,发现登录也没问题了。
最后提交 git
git add .
git commit -m '实现登录注册相关逻辑以及多国语音控制'
下一节,来处理邮件验证。