- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章通过修改Laravel Auth使用salt和password进行认证用户详解由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
前言 。
本文主要给大家介绍了通过修改Laravel Auth用salt和password进行认证用户的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍:
Laraval自带的用户认证系统Auth非常强大易用,不过在Laravel的用户认证系统中用户注册、登录、找回密码这些模块中用到密码加密和认证算法时使用的都是bcrypt,而很多之前做的项目用户表里都是采用存储salt + password加密字符串的方式来记录用户的密码的,这就给使用Laravel框架来重构之前的项目带来了很大的阻力,不过最近自己通过在网上找资料、看社区论坛、看源码等方式完成了对Laravel Auth的修改,在这里分享出来希望能对其他人有所帮助。 开篇之前需要再说明下如果是新项目应用Laravel框架,那么不需要对Auth进行任何修改,默认的bcrypt加密算法是比salt + password更安全更高效的加密算法.
修改用户注册 。
首先,在laravel 里启用验证是用的artisan命令 。
1
|
php artisan make:auth
|
执行完命令后在routes文件(位置:app/Http/routes.php)会多一条静态方法调用 。
1
|
Route::auth();
|
这个Route是Laravel的一个Facade (位于Illuminate\Support\Facades\Route), 调用的auth方法定义在Illuminate\Routing\Router类里, 如下可以看到auth方法里就是定义了一些Auth相关的路由规则 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
/**
* Register the typical authentication routes for an application.
*
* @return void
*/
public
function
auth()
{
// Authentication Routes...
$this
->get(
'login'
,
'Auth\AuthController@showLoginForm'
);
$this
->post(
'login'
,
'Auth\AuthController@login'
);
$this
->get(
'logout'
,
'Auth\AuthController@logout'
);
// Registration Routes...
$this
->get(
'register'
,
'Auth\AuthController@showRegistrationForm'
);
$this
->post(
'register'
,
'Auth\AuthController@register'
);
// Password Reset Routes...
$this
->get(
'password/reset/{token?}'
,
'Auth\PasswordController@showResetForm'
);
$this
->post(
'password/email'
,
'Auth\PasswordController@sendResetLinkEmail'
);
$this
->post(
'password/reset'
,
'Auth\PasswordController@reset'
);
}
|
通过路由规则可以看到注册时请求的控制器方法是AuthController的register方法, 该方法定义在\Illuminate\Foundation\Auth\RegistersUsers这个traits里,AuthController在类定义里引入了这个traits. 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
/**
* Handle a registration request for the application.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public
function
register(Request
$request
)
{
$validator
=
$this
->validator(
$request
->all());
if
(
$validator
->fails()) {
$this
->throwValidationException(
$request
,
$validator
);
}
Auth::guard(
$this
->getGuard())->login(
$this
->create(
$request
->all()));
return
redirect(
$this
->redirectPath());
}
|
在register方法里首先会对request里的用户输入数据进行验证,你只需要在AuthController的validator方法里定义自己的每个输入字段的验证规则就可以 。
1
2
3
4
5
6
7
8
|
protected
function
validator(
array
$data
)
{
return
Validator::make(
$data
, [
'name'
=>
'required|max:255'
,
'email'
=>
'required|email|max:255|unique:user'
,
'password'
=>
'required|size:40|confirmed'
,
]);
}
|
接着往下看验证通过后,Laravel会掉用AuthController的create方法来生成新用户,然后拿着新用户的数据去登录Auth::guard($this->getGuard())->login($this->create($request->all())),
所以我们要自定义用户注册时生成用户密码的加密方式只需要修改AuthController的create方法即可.
比如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
/**
* Create a new user instance after a valid registration.
*
* @param array $data
* @return User
*/
protected
function
create(
array
$data
)
{
$salt
= Str::random(6);
return
User::create([
'nickname'
=>
$data
[
'name'
],
'email'
=>
$data
[
'email'
],
'password'
=> sha1(
$salt
.
$data
[
'password'
]),
'register_time'
=> time(),
'register_ip'
=>
ip2long
(request()->ip()),
'salt'
=>
$salt
]);
}
|
修改用户登录 。
修改登录前我们需要先通过路由规则看一下登录请求的具体控制器和方法,在上文提到的auth方法定义里可以看到 。
1
2
3
|
$this
->get(
'login'
,
'Auth\AuthController@showLoginForm'
);
$this
->post(
'login'
,
'Auth\AuthController@login'
);
$this
->get(
'logout'
,
'Auth\AuthController@logout'
);
|
验证登录的操作是在\App\Http\Controllers\Auth\AuthController类的login方法里。打开AuthController发现Auth相关的方法都是通过性状(traits)引入到类内的,在类内use 要引入的traits,在编译时PHP就会把traits里的代码copy到类中,这是PHP5.5引入的特性具体适用场景和用途这里不细讲。 所以AuthController@login方法实际是定义在 \Illuminate\Foundation\Auth\AuthenticatesUsers这个traits里的 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
/**
* Handle a login request to the application.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public
function
login(Request
$request
)
{
$this
->validateLogin(
$request
);
$throttles
=
$this
->isUsingThrottlesLoginsTrait();
if
(
$throttles
&&
$lockedOut
=
$this
->hasTooManyLoginAttempts(
$request
)) {
$this
->fireLockoutEvent(
$request
);
return
$this
->sendLockoutResponse(
$request
);
}
$credentials
=
$this
->getCredentials(
$request
);
if
(Auth::guard(
$this
->getGuard())->attempt(
$credentials
,
$request
->has(
'remember'
))) {
return
$this
->handleUserWasAuthenticated(
$request
,
$throttles
);
}
if
(
$throttles
&& !
$lockedOut
) {
$this
->incrementLoginAttempts(
$request
);
}
return
$this
->sendFailedLoginResponse(
$request
);
}
|
登录验证的主要操作是在Auth::guard($this->getGuard())->attempt($credentials, $request->has('remember'));这个方法调用中来进行的,Auth::guard($this->getGuard()) 获取到的是\Illuminate\Auth\SessionGuard (具体如何获取的看Auth这个Facade \Illuminate\Auth\AuthManager里的源码) 。
看一下SessionGuard里attempt 方法是如何实现的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
public
function
attempt(
array
$credentials
= [],
$remember
= false,
$login
= true)
{
$this
->fireAttemptEvent(
$credentials
,
$remember
,
$login
);
$this
->lastAttempted =
$user
=
$this
->provider->retrieveByCredentials(
$credentials
);
if
(
$this
->hasValidCredentials(
$user
,
$credentials
)) {
if
(
$login
) {
$this
->login(
$user
,
$remember
);
}
return
true;
}
if
(
$login
) {
$this
->fireFailedEvent(
$user
,
$credentials
);
}
return
false;
}
/**
* Determine if the user matches the credentials.
*
* @param mixed $user
* @param array $credentials
* @return bool
*/
protected
function
hasValidCredentials(
$user
,
$credentials
)
{
return
!
is_null
(
$user
) &&
$this
->provider->validateCredentials(
$user
,
$credentials
);
}
|
retrieveByCredentials是用传递进来的字段从数据库中取出用户数据的,validateCredentials是用来验证密码是否正确的实际过程.
这里需要注意的是$this->provider这个provider是一个实现了\Illuminate\Contracts\Auth\UserProvider类的provider, 我们看到目录Illuminate\Auth下面有两个UserProvider的实现,分别为DatabaseUserProvider和EloquentUserProvider, 但是我们验证密码的时候是通过那个来验证的呢,看一下auth的配置文件 。
1
2
3
4
5
6
|
'providers'
=> [
'users'
=> [
'driver'
=>
'eloquent'
,
'model'
=> App\User::
class
,
//这个是driver用的Model
],
],
|
这里配置的是driver => eloquent , 那么就是通过EloquentUserProvider的retrieveByCredentials来验证的, 这个EloquentUserProvider 是在SessionGuard实例化时被注入进来的, (具体是怎么通过读取auth配置文件, 实例化相应的provider注入到SessionGuard里的请查阅\Illuminate\Auth\AuthManager 里createSessionDriver方法的源代码) 。
接下来我们继续查看EloquentUserProvider中retrieveByCredentials和validateCredentials方法的实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
/**
* Retrieve a user by the given credentials.
*
* @param array $credentials
* @return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public
function
retrieveByCredentials(
array
$credentials
)
{
if
(
empty
(
$credentials
)) {
return
;
}
$query
=
$this
->createModel()->newQuery();
foreach
(
$credentials
as
$key
=>
$value
) {
if
(! Str::contains(
$key
,
'password'
)) {
$query
->where(
$key
,
$value
);
}
}
return
$query
->first();
}
/**
* Validate a user against the given credentials.
*
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @param array $credentials
* @return bool
*/
public
function
validateCredentials(UserContract
$user
,
array
$credentials
)
{
$plain
=
$credentials
[
'password'
];
return
$this
->hasher->check(
$plain
,
$user
->getAuthPassword());
}
|
上面两个方法retrieveByCredentials用除了密码以外的字段从数据库用户表里取出用户记录,比如用email查询出用户记录,然后validateCredentials方法就是通过$this->haser->check来将输入的密码和哈希的密码进行比较来验证密码是否正确.
好了, 看到这里就很明显了, 我们需要改成自己的密码验证就是自己实现一下validateCredentials就可以了, 修改$this->hasher->check为我们自己的密码验证规则就可以了.
首先我们修改$user->getAuthPassword()把数据库中用户表的salt和password传递到validateCredentials中 修改App\User.php 添加如下代码 。
1
2
3
4
|
/**
* The table associated to this model
*/
protected
$table
=
'user'
;//用户表名不是laravel约定的这里要指定一下
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
/**
* 禁用Laravel自动管理timestamp列
*/
public
$timestamps
= false;
/**
* 覆盖Laravel中默认的getAuthPassword方法, 返回用户的password和salt字段
* @return type
*/
public
function
getAuthPassword()
{
return
[
'password'
=>
$this
->attributes[
'password'
],
'salt'
=>
$this
->attributes[
'salt'
]];
}
|
然后我们在建立一个自己的UserProvider接口的实现,放到自定义的目录中:
新建app/Foundation/Auth/AdminEloquentUserProvider.php 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
namespace
App\Foundation\Auth;
use
Illuminate\Auth\EloquentUserProvider;
use
Illuminate\Contracts\Auth\Authenticatable;
use
Illuminate\Support\Str;
class
AdminEloquentUserProvider
extends
EloquentUserProvider
{
/**
* Validate a user against the given credentials.
*
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @param array $credentials
*/
public
function
validateCredentials(Authenticatable
$user
,
array
$credentials
) {
$plain
=
$credentials
[
'password'
];
$authPassword
=
$user
->getAuthPassword();
return
sha1(
$authPassword
[
'salt'
] .
$plain
) ==
$authPassword
[
'password'
];
}
}
|
最后我们修改auth配置文件让Laravel在做Auth验证时使用我们刚定义的Provider, 修改config/auth.php:
1
2
3
4
5
6
|
'providers'
=> [
'users'
=> [
'driver'
=>
'admin-eloquent'
,
'model'
=> App\User::
class
,
]
]
|
修改app/Provider/AuthServiceProvider.php 。
1
2
3
4
5
6
7
8
|
public
function
boot(GateContract
$gate
)
{
$this
->registerPolicies(
$gate
);
\Auth::provider(
'admin-eloquent'
,
function
(
$app
,
$config
) {
return
New \App\Foundation\Auth\AdminEloquentUserProvider(
$app
[
'hash'
],
$config
[
'model'
]);
});
}
|
Auth::provider方法是用来注册Provider构造器的,这个构造器是一个Closure,provider方法的具体代码实现在AuthManager文件里 。
1
2
3
4
5
6
|
public
function
provider(
$name
, Closure
$callback
)
{
$this
->customProviderCreators[
$name
] =
$callback
;
return
$this
;
}
|
闭包返回了AdminEloquentUserProvider对象供Laravel Auth使用,好了做完这些修改后Laravel的Auth在做用户登录验证的时候采用的就是自定义的salt + password的方式了.
修改重置密码 。
Laravel 的重置密码的工作流程是:
第一步需要配置Laravel的email功能,此外还需要在数据库中创建一个新表password_resets来存储用户的email和对应的token 。
1
2
3
4
5
6
7
|
CREATE TABLE `password_resets` (
`email` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`token` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`created_at` timestamp NOT NULL,
KEY `password_resets_email_index` (`email`),
KEY `password_resets_token_index` (`token`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
|
通过重置密码表单的提交地址可以看到,表单把新的密码用post提交给了/password/reset,我们先来看一下auth相关的路由,确定/password/reset对应的控制器方法.
1
|
$this
->post(
'password/reset'
,
'Auth\PasswordController@reset'
);
|
可以看到对应的控制器方法是\App\Http\Controllers\Auth\PasswordController类的reset方法,这个方法实际是定义在\Illuminate\Foundation\Auth\ResetsPasswords 这个traits里,PasswordController引入了这个traits 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
/**
* Reset the given user's password.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public
function
reset(Request
$request
)
{
$this
->validate(
$request
,
$this
->getResetValidationRules(),
$this
->getResetValidationMessages(),
$this
->getResetValidationCustomAttributes()
);
$credentials
=
$this
->getResetCredentials(
$request
);
$broker
=
$this
->getBroker();
$response
= Password::broker(
$broker
)->reset(
$credentials
,
function
(
$user
,
$password
) {
$this
->resetPassword(
$user
,
$password
);
});
switch
(
$response
) {
case
Password::PASSWORD_RESET:
return
$this
->getResetSuccessResponse(
$response
);
default
:
return
$this
->getResetFailureResponse(
$request
,
$response
);
}
}
|
方法开头先通过validator对输入进行验证,接下来在程序里传递把新密码和一个闭包对象传递给Password::broker($broker)->reset();方法,这个方法定义在\Illuminate\Auth\Passwords\PasswordBroker类里. 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
/**
* Reset the password for the given token.
*
* @param array $credentials
* @param \Closure $callback
* @return mixed
*/
public
function
reset(
array
$credentials
, Closure
$callback
)
{
// If the responses from the validate method is not a user instance, we will
// assume that it is a redirect and simply return it from this method and
// the user is properly redirected having an error message on the post.
$user
=
$this
->validateReset(
$credentials
);
if
(!
$user
instanceof
CanResetPasswordContract) {
return
$user
;
}
$pass
=
$credentials
[
'password'
];
// Once we have called this callback, we will remove this token row from the
// table and return the response from this callback so the user gets sent
// to the destination given by the developers from the callback return.
call_user_func(
$callback
,
$user
,
$pass
);
$this
->tokens->
delete
(
$credentials
[
'token'
]);
return
static
::PASSWORD_RESET;
}
|
在PasswordBroker的reset方法里,程序会先对用户提交的数据做再一次的认证,然后把密码和用户实例传递给传递进来的闭包,在闭包调用里完成了将新密码更新到用户表的操作, 在闭包里程序调用了的PasswrodController类的resetPassword方法 。
1
2
3
|
function
(
$user
,
$password
) {
$this
->resetPassword(
$user
,
$password
);
});
|
PasswrodController类resetPassword方法的定义 。
1
2
3
4
5
6
7
8
9
|
protected
function
resetPassword(
$user
,
$password
)
{
$user
->forceFill([
'password'
=> bcrypt(
$password
),
'remember_token'
=> Str::random(60),
])->save();
Auth::guard(
$this
->getGuard())->login(
$user
);
}
|
在这个方法里Laravel 用的是bcrypt 加密了密码, 那么要改成我们需要的salt + password的方式,我们在PasswordController类里重写resetPassword方法覆盖掉traits里的该方法就可以了.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
/**
* 覆盖ResetsPasswords traits里的resetPassword方法,改为用sha1(salt + password)的加密方式
* Reset the given user's password.
*
* @param \Illuminate\Contracts\Auth\CanResetPassword $user
* @param string $password
* @return void
*/
protected
function
resetPassword(
$user
,
$password
)
{
$salt
= Str::random(6);
$user
->forceFill([
'password'
=> sha1(
$salt
.
$password
),
'salt'
=>
$salt
,
'remember_token'
=> Str::random(60),
])->save();
\Auth::guard(
$this
->getGuard())->login(
$user
);
}
|
结语 。
到这里对Laravel Auth的自定义就完成了,注册、登录和重置密码都改成了sha1(salt + password)的密码加密方式, 所有自定义代码都是通过定义Laravel相关类的子类和重写方法来完成没有修改Laravel的源码,这样既保持了良好的可扩展性也保证了项目能够自由迁移.
注:使用的Laravel版本为5.2 。
总结 。
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对我的支持.
原文链接:https://segmentfault.com/a/1190000007907959 。
最后此篇关于通过修改Laravel Auth使用salt和password进行认证用户详解的文章就讲到这里了,如果你想了解更多关于通过修改Laravel Auth使用salt和password进行认证用户详解的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
主要问题是可以从已保存的 Auth 对象设置零 Auth 对象: let oldAuth = Auth.auth().currentUser let oldAuthId = Auth.auth().c
何时使用 this.afAuth.auth.signInWithCredential 在我的 Ionic 应用程序中一切正常。我可以使用 Google 身份验证登录并将用户个人资料推送到 fireba
我想在启动时使用我的测试用户帐户预加载 firebase auth 模拟器,就像我对 Firestore 模拟器及其导入/导出选项所做的一样。我尝试在模拟器运行时使用 auth:import 和 au
我正在尝试通过创建 Firebase DataService 来 DRY 我的应用程序,但我不知道为 Auth.auth() 转换什么类型。我查看了源代码定义,但它在我不理解的 Objective C
我有一个更新用户个人资料图片的组件:。我有第二个组件检测用户状态的变化:。问题是,在执行updateProfile()之后,没有触发auth.onAuthStateChanged()。因此,我得到了老
我正在使用 Facebook Javascript SDK,并且正在调整我网站的用户登录系统。我想知道 auth.login/auth.logout 和 auth.sessionChange 之间有什
目前,我正在完成Daniel Kehoe的Learn Ruby on Rails教程。练习之一是使用Google的Gmail帐户从“联系人”页面发送联系人表格。 但是,当我发送联系表格时,没有在邮箱中
我在我的应用中使用 Firebase Auth。我更新电子邮件如下: firebaseAuth.currentUser?.updateEmail(email) 电子邮件正在 100% 更新(必要时我也
在我的应用程序中,当我第一次让用户加入时,我会让他们登录并确认这有效,并且他们会获得一个用户 ID。但稍后在我的 Storyboard 中,我调用了 Auth.auth.currentUser.uid
我是编程新手,我正在尝试从 firebase 数据库中读取数据。我从 Firebase 手册中得到这段代码,我想知道术语 uid,AUTH.auth() 在这里是什么意思。它是一个变量吗?我从 fir
已结束。此问题不符合 Stack Overflow guidelines .它目前不接受答案。 我们不允许提出有关书籍、工具、软件库等方面的建议的问题。您可以编辑问题,以便用事实和引用来回答它。 关闭
背景 我构建了一个连接到 Authorize.net 支付网关的电子商务应用程序。管理员可以通过以下方式处理信用卡: 管理员立即从客户的信用卡中扣款的“捕获”交易。 “仅授权”交易,管理员从信用卡中授
我正在使用 dj-rest-auth ( https://dj-rest-auth.readthedocs.io/en/latest/ ) 并尝试实现自定义注册表单。当我尝试注册新用户时,我有基本表单
我们正在使用 Azure Web App Easy Auth,并使用 Web App 作为反向代理,将流量转发到 Angular 应用程序。 角度应用程序使用/.auth/me 并使用 token 并
我有一个 Controller 和一个如下所示的 View ,它在一段时间内工作完美,但是在向服务器发出一些请求后(即每秒重新加载一次),它将在此行失败 if (!$this->tank_auth-
我希望在单个 Web 应用程序中,部分部分使用身份验证,部分部分完全开放(或者更具体地说,不使用基于容器的身份验证)。 使用基于容器的身份验证的应用程序部分位于 URL /而打开的部分位于 URL /
只要我按下按钮调用 signOut 方法,当前 View Controller 就会被关闭。但是,注销过程是成功的。 (我正在使用 FirebaseAuth SDK。) 这是我的代码: @IBActi
对于Firebase iOS,如果我想做用户认证,这3个选择有什么区别吗? FirebaseUI FirebaseUI/授权 Firebase/授权 如果有人可以解释使用“预构建”FirebaseUI
我正在使用 Vue-auth 包来验证我的 vue-cli 应用程序。一切正常,但当我在我的 vue 操作中访问此代码时,它返回 undefined。有什么想法吗? const AuthService
所以我正在使用 Laravel 身份验证,第一次它工作正常,但删除 Auth 文件夹后,我再次运行 php artisan make:auth 但它不会创建另一个 Auth 文件夹。 View 和模型
我是一名优秀的程序员,十分优秀!