美文网首页
从零开始搭建聊天系统之客户端登录

从零开始搭建聊天系统之客户端登录

作者: 隔岸坐看云卷云舒 | 来源:发表于2019-03-23 12:53 被阅读0次

必备:
1.lumen5.x version > 5.5+
2.redis
3.mysql

现在我们指定:
1.用户是用手机号做账户来登录
2.用户数据都使用缓存
3.用户登录也查询缓存,缓存查询不到再去数据库查询,并更新缓存
4.Redis用hash表维护用户数据
5.用户登录后,系统颁发一个Token凭据作为用户身份识别
6.token可以放到cookie
7.更新用户在线状态

那么流程应该是这样:


WechatIMG375.jpeg

router

$router->post('login', 'User\UserController@login');

create Model

<?php

namespace App\Http\Model;


use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Redis;

class User extends Model
{
    public $table = 'user';
    public $dateFormat = 'U';


    /**
     * @param array $data
     * @return array
     * @author mjShu
     */
    public static function login(array $data):array {
        $user = Redis::hget('user_name',$data['name']);
        if($user && $user['password'] == $data['password']){
            $user =  json_decode($user,true);
        }else{
            $user = User::select('name','username','sign','avatar')->where([
                'name'=>$data['name'],
                'password'=>$data['password']
            ])->first();
            if ($user){
                Redis::hset('user_name',$user->id,json_encode($user));
                $user = $user->toArray();
            }else{
                return [];
            }
        }

        return $user;
    }
}

create Controller

class UserController extends Controller
{
    const time = 3600000;
    

    public function login(Request $request):array
    {
        $data = $request->all();
        if (strlen($data['name']) == 11  && strlen($data['password']) >=6) {
            $data['password'] = md5($data['password']);
            $user = User::login($data);
            if ($user){
                $token = md5($data['name'] . $request->getClientIp().time());
                Redis::setex('token:'.$token,self::time,$user['id']);
                return ['code'=>200,'user'=>$user,'token'=>$token];
            }else{
                return ['code'=>400];
            }
        }

    }

创建表:


WechatIMG377.jpeg

插入模拟数据 name 为17612148988 password 为md5(227227)

现在我们通过POSTMAN测试下:


WechatIMG378.jpeg

检查Redis


WechatIMG379.jpeg

现在业务逻辑部分正常,现在我们来写html部分

<script src="/admin/js/jquery.js"></script>
<script src="/admin/js/jquery.cookie.js"></script>
<form  >
    <dl class="admin_login">
        <dt>
            <strong>用户登录</strong>
            <em>User Login</em>
        </dt>
        <dd class="user_icon">
            <input type="text" id='name' placeholder="账号" class="login_txtbx"/>
        </dd>
        <dd class="pwd_icon">
            <input type="password" id='password' placeholder="密码" class="login_txtbx"/>
        </dd>

        <dd>
            <input type="submit" value="立即登陆" class="submit_btn" />
        </dd>
        <dd>
            <a href="/register"><input type="button" value="立即注册" class="submit_btn"/></a>
        </dd>
        <dd>
            <p>© 2015- {{date('Y')}} 版权所有</p>

        </dd>
    </dl>
</form>
</body>
<script>
    $('form').submit(function () {
        var name = $("#name").val();
        var password = $("#password").val();
        if(name.length == 11 && password.length >=6){
            $.post('/login',{name:name,password:password},function (data) {
                console.log(data)
                if(data.code == 200){
                    console.log(data.token);
                    $.cookie('token',data.token);
                    $.cookie('uid',data.user.id);
                    console.log($.cookie('token'));
                    //成功跳转
                }else{
                    //失败
                }
            })
        }
        return false;
    })
</script>

现在我们来试试:


WechatIMG380.jpeg
WechatIMG381.jpeg

通过console.log打印我们可以在控制台和cookie看到成功打印出我们想要的数据,cookie也写入了token

创建Middleware中间件校验用户的登录状态

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;

class Login
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        $token = $_COOKIE['token'];
        $uid = $_COOKIE['uid'];
        if($token!=''){
            $tokenCache =  Redis::get('token:'.$token);
            if($uid == $tokenCache){
                return $next($request);
            }
        }
        return redirect('/');

    }
}

修改app.php引导文件注册路由中间件

$app->routeMiddleware([
   'login' => App\Http\Middleware\Login::class,
 ]);

新增route与校验登录令牌group

$router->group(['middleware' => 'login'],function ($router) {

    $router->get('index',['as' => 'index', function () {
        return view('Index.index');
    }]);

创建Index目录与index.balde.php文件

    <script src="/json/json2.js"></script>
    <script src='https://cdn.bootcss.com/socket.io/2.0.3/socket.io.js'></script>
    <script src='/admin/js/jquery.js'></script>
    <script src="/admin/js/jquery.cookie.js"></script>
<script>
       ws =  new WebSocket('ws://'+location.hostname+':8082');

        ws.onopen = function (e) {
             ws.send(JSON.stringify({type:0,token:$.cookie('token'),uid:$.cookie('uid')}));
        }
        ws.onmessage = function (e) {
            console.log(e);
            var data = JSON.parse(e.data);
            //系统消息
            switch (data.msgType){
                case 1:
                  
                    break;
                case 2:  //盒子消息
                    layim.showNew('Friend', true);
                    break;
                case 3:  //点对点消息
                   
                    layim.getMessage(obj);
                    break;
                case 4:  //上下线状态更新
                    if(data.online == 0){
                        layim.setFriendStatus(data.uid, 'offline');
                    }else{
                        layim.setFriendStatus(data.uid, 'online');
                    }
                    break;
                case 5:  //群组消息
                 
                    break;
                case 6:  //添加好友到列表
                  
                    break;
                case 7: //添加群组到列表
                
                    //通知服务器准备推送群组消息
                    ws.send(JSON.stringify({type:7,group_id:data.id}));
                    break;
                case 8:  //接受群组消息
                    layim.getMessage({
                        system: true
                        ,id: data.group_id
                        ,type: "group"
                        ,content: data.content
                    });
                    break;
                default:
                    console.log(data)
            }
        }
    });

</script>

修改WebsocketController

public static function onMessage($client_id, $data)
    {
        if(!is_array($data)){
            $data = json_decode($data,true);
        }
        switch ($data['type']){
            case 0:
                $status = UserController::checkSocketToken($data);  //检查token合法性
                if($status){
                    //绑定uid,更改上线状态,通知该用户所有的好友
                    Gateway::bindUid($client_id, $data['uid']); 
                    Redis::set('bind:'.$client_id,$data['uid']);
                    GroupController::joinGroup($client_id);
                }
                break;
               //省略......
public static function checkSocketToken(array $data):bool {
        $tokenCache =  Redis::get('token:'.$data['token']);
        if($data['uid'] == $tokenCache){
            return true;
        }else{
            return false;
        }
    }

现在访问我们的登录页面登录成功后应该调整到ws链接页面,我们打开谷歌浏览器的控制台可以发现成功连接;


WechatIMG384.jpeg
WechatIMG383.jpeg

我们来分析ws代码

      //实例一个socket连接
       ws =  new WebSocket('ws://'+location.hostname+':8082');
      //在连接建立完成后发送数据给socket,其中携带了cookie的数据,实际是让服务器校验身份合法
        ws.onopen = function (e) {
            ws.send(JSON.stringify({type:0,token:$.cookie('token'),uid:$.cookie('uid')}));
        }
    //为了保活这个链接,我们需要心跳机制, js一个定时器,每10秒执行一次,与socket服务通讯
    var sh;
    sh = setInterval("sendHeartbeat()", 10000);

  function sendHeartbeat() {
    if(ws.readyState == 1){
        ws.send(JSON.stringify({type:'4'}));
    }
    if(ws.readyState == 3){
        layer.alert('与服务器链接中断,请检查网络');
        clearInterval(sh);

    }


相关文章

网友评论

      本文标题:从零开始搭建聊天系统之客户端登录

      本文链接:https://www.haomeiwen.com/subject/luarvqtx.html