设为首页 收藏本站
查看: 726|回复: 0

[经验分享] php模拟登录 转

[复制链接]

尚未签到

发表于 2017-3-26 11:39:10 | 显示全部楼层 |阅读模式
模拟登录不是真正意义上的单点登录,它又叫做伪单点登录,应用漫游,代填口令等等。

      场景是这样的:用户访问一个应用,比如说新浪邮件,首次访问时,应用会提示输入新浪的用户名和密码。保存后,将用户名和密码填充到动态表单,使用动态生成的表单提交,从而实现自动登录。

      如果用户修改了新浪里的密码,则提交会失败。这就有一个问题,需要先用指定的用户名和密码尝试登录,如果尝试登录成功,则post;如果不成功,则重定向到录入界面,直到提交成功。

      写这个程序的关键点在两个地方,一个而是尝试登录程序,一个是动态表单生成程序。

      关键问题找到了,首先我们考虑第一个问题。要模拟浏览器尝试登录,要有一个类似java里的Apache HttpClient的东西。我google很长时间,找到了一个php的HttpClient。开始我艰难的尝试之旅。

      分析http请求相关信息,我用的是HttpWatch。

      

      参考php HttpClient说明,很快我写了一段代码,用来尝试登录。尝试了n次,也没有成功。一开始我是直接post的,因为session id是通过cookie传递的,因为没有session信息,所以总是不成功,真土啊,对http协议理解不够深,相当于补课了。问了有此方面经验的同事,他说一般有两种,一种是使用HttpClient,一种是用httpwatch分析后,把cookie值抄下来,然后尝试登录。怎么想第二种方法都是太土了,但第一种方式又实现不了。
      我又开始google,发现都是介绍java的httpclient的,php的几乎没有。但这次google有一个发现,就是apache的httpclient可以保存多次请求的信息,比如cookie,有记忆的。而我找的HttpClient只能单次请求,也就是说,每次都要手动设置cookie。我突然有想到,我何不从登录页面开始呢?这样我从登录页面开始get,然后将得到的cookie,再set一遍,然后开始post。
      还是不行!
      我开启了这个Http类的debug,发现post之后,重定向得到bad request,原来是重定向得到的path,没有“/”,这是原作者的一个bug。还一个问题比较大,就是他是重定向到另外的域,如果我还用之前设置的域,访问路径完全是错的。这样我在HttpClient里增加了两个参数,一个是判断是否重定向到其它域,如果重定向到其它域。把another_host赋给当前的host。
      终于成功了!
      我通过取回内容title中的值来判断是否登录成功,并把这些配置到数据库中。下面是我的数据库模型图:



    动态表单生成就比较简单了,直接拼凑html:

Php代码  
<?php  
require_once 'mysql.connect.php';  
require_once 'AppBean.class.php';  
  
/**
* 生成动态表单
* author 张永吉(gurudk)
*/  
class DynamicForm {  
      
    var $appid;  
    var $loginUrl;  
    var $host;  
    var $cookieHost;  
    var $port;  
    var $formUserName;  
    var $formPassword;  
    var $errorInfo;  
    var $appProperties = array();  
    var $appBean;  
    var $loginUserValue;  
    var $loginPassValue;  
      
    public function __construct($appid) {  
        $this->appBean = new AppBean($appid);  
        $this->loginUrl = $this->appBean->loginUrl;  
        $this->host = $this->appBean->host;  
        $this->cookieHost = $this->appBean->cookieHost;  
        $this->port = $this->appBean->port;  
        $this->formUserName = $this->appBean->formUserName;  
        $this->formPassword = $this->appBean->formPassword;  
        $this->errorInfo = $this->appBean->errorInfo;  
        $this->appProperties = $this->appBean->appProperties;  
    }  
      
    public function __destruct(){  
  
    }  
      
    /**
     * 生成html
     * document.dynamicform.submit()
     * @return unknown
     */  
    public function generate() {  
        $content = "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">".  
                "<html>".  
                    "<head>".  
                        "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">".  
                        "<title>Insert title here</title>".  
                    "</head>".  
                "<body>".  
                "<form name=\"dynamicform\" method=\"POST\" action=\"".$this->loginUrl."\" >".  
                $this->generateMultibox().  
                $this->generateUserPasswordControl().  
                "       <input type=\"submit\" name=\"btnlogin\" value=\"login\">".  
                   "</form>".  
                "</body>".  
                "</html>";  
         
        return $content;  
    }  
      
    /**
     * 生成下拉框或者radio组选框
     *
     * @return unknown
     */  
    private function generateMultibox(){  
        $i = 0;  
        $html = "";  
        while($key = key($this->appProperties)){  
            if("combox" == $this->appProperties[$key]["type"]){  
                $html = "<select id=\"freeselect\" name=\"".$this->appProperties[$key]["key"]."\">";  
                  
                $values = split(",", $this->appProperties[$key]["value"]);  
                do{  
                    //对于下拉框,value中可接受逗号间隔的列表,第一个值为选中值。  
                    if($i == 0){  
                        $html = $html."<option value=\"".current($values)."\" selected=\"selected\">".current($values)."</option>";  
                    }else{  
                        $html = $html."<option value=\"".current($values)."\">".current($values)."</option>";  
                    }  
                    $i++;  
                }while(next($values));  
                  
                $html = $html."</select>";  
            }else if("hidden" == $this->appProperties[$key]["type"]){  
                $html .= "<input type='hidden' name=\"".$this->appProperties[$key]["key"]."\" value=\"".$this->appProperties[$key]["value"]."\">";  
            }  
              
            next($this->appProperties);  
        }  
         
        return $html;  
    }  
      
    /**
     * 生成用户名和密码输入框
     *
     * @return unknown
     */  
    private function generateUserPasswordControl(){  
        $html = "       <input type='hidden' name=\"".$this->formUserName."\" value=\"".$this->loginUserValue."\">".  
                "       <input type=\"password\" name=\"".$this->formPassword."\" value=\"".$this->loginPassValue."\" />";  
         
        return $html;  
    }  
  
    /**
     * 填充用户名和密码表单值
     *
     * @param unknown_type $userValue
     * @param unknown_type $passValue
     */  
    public function setAutoLoginValue($userValue, $passValue){  
        $this->loginUserValue = $userValue;  
        $this->loginPassValue = $passValue;   
    }  
}  
  
?>  


尝试登录的代码:


Python代码  
<?php  
  
require_once 'HttpClient.php';  
require_once 'AppBean.class.php';  
  
/**  
* 测试当前用户名和密码是否可以登录远程服务器  
*   
* author 张永吉(gurudk)  
*/  
class LoginTry {  
      
    var $appBean;  
    var $browser;  
    var $userName;  
    var $password;  
      
    /**  
     *   
     */  
    function __construct($appid, $userName, $password) {  
        $this->appBean = new AppBean ( $appid );  
        $this->userName = $userName;  
        $this->password = $password;  
              
        $this->setUpBrowser();  
    }  
      
    /**  
     *   
     */  
    function __destruct() {  
         
    //TODO - Insert your code here  
    }  
      
    private function setUpBrowser() {  
        $this->browser = new HttpClient ( $this->appBean->host, $this->appBean->port );  
        $client->max_redirects = 10;  
        $this->browser->cookie_host = $this->appBean->cookieHost;  
        $this->browser->setUserAgent ( 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; InfoPath.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)' );  
    }  
      
    /**  
     * 对指定网站进行尝试登录  
     *  
     */  
    public function tryLogin() {  
        if($this->getTitle() == $this->appBean->errorInfo){  
            return false;  
        }  
         
        return true;  
    }  
      
    public function getTitle(){  
        $this->browser->get ( "/" );  
        $this->browser->setCookies ( $this->browser->getCookies () );  
        $this->browser->redirect_to_other_site = $this->appBean->isRedirectOther;  
        $this->browser->another_host = $this->appBean->anotherHost;  
        $this->browser->post ( $this->appBean->postUrl, $this->buildPostParams());  
        $this->browser->getContent ();  
        preg_match_all("/<title>(.*)<\/title>/i", $this->browser->getContent (), $matches);  
        $result = $matches[1][0];  
         
        //编码转换  
        if("utf-8" == $this->appBean->encode){  
            $title = iconv("utf-8", "gb2312", $result);  
        }else{  
            $title = $result;  
        }         
         
        return $title;  
    }  
      
    /**  
     * 读取数据库数据,构造post参数array  
     *  
     */  
    public function buildPostParams(){  
        $params = array ($this->appBean->formUserName => $this->userName, $this->appBean->formPassword => $this->password );  
        while($key = key($this->appBean->appProperties)){  
            $this->copyOtherParams($params, $this->appBean->appProperties[$key]);  
            next($this->appBean->appProperties);  
        }  
         
        return $params;  
    }  
  
    /**  
     * copy除用户名,密码外其它需要配置的参数,在数据库应用属性表中进行配置  
     *  
     * @param unknown_type $params  
     * @param unknown_type $propArray  
     */  
    private function copyOtherParams(&$params, $propArray){  
        $controlType = $propArray["type"];  
        if("combox" == $controlType || "radio" == $controlType){  
            $params[$propArray["key"]] = current(split(",", $propArray["value"]));  
        }else{  
            $params[$propArray["key"]] = $propArray["value"];  
        }  
    }  
}  
  
?>  
  
         

用这种做法,登录新浪邮件是没问题的,但是登录网易时,我使用localhost是可以的,使用ip地址和其它域名不行。
可能网易邮件会验证refer地址,但验证refer地址的算法有点问题,:)。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-355582-1-1.html 上篇帖子: QueryPath, php上的jQuery 下篇帖子: [php]前端控制器
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表