澳门新浦京电子游戏URI参数签名算法

本文讲述的是如何为你的PHP项目实现Google的Oauth系统。这个示例PHP脚本非常快,对增加你的PHP项目注册当然是很有帮助的。

 

本文翻译自Auth-Boss。
如果有翻译的不恰当或不对的地方, 欢迎指出。

成为一个认证老司机, 了解网络上不同的身份认证方法。

本文档的目的是记录和编目Web上的身份验证方法。
认证指的是创建一个系统的过程,用户可以通过该系统“登录”在线服务,并授予对受保护资源的访问权限。
以下引用可能更好地总结我想要解释的内容:

客户端认证涉及向Web上的服务器证明客户端(或用户)的身份。[1]

简介

应用基于HTTP POST或HTTP GET请求发送Open
API调用请求时,为了确保应用与百度REST服务器之间的安全通信,防止Secret
Key盗用、数据篡改等恶意攻击行为,百度REST服务器使用了参数签名机制。应用在调用百度Open
API之前,需要为其所有请求参数计算一个MD5签名,并追加到请求参数中,参数名为“sign”。百度REST服务器在接收到请求时会重新计算签名,并判断其值是否与应用传递过来的sign参数值一致,以此判定当前Open
API调用请求是否是被第三者伪造或篡改。

应用在调用Open API之前需要通过 百度OAuth2.0服务获得用户或平台的授权,获取到授权后将会拿到以下3个重要参数:

  • access_token:基于https调用Open API时所需要的访问授权码;
  • session_key:基于http调用Open API时所需要的访问授权码;
  • session_secret:基于http调用Open
    API时计算参数签名用的签名密钥。

其中,session_secret这个参数就是做参数签名时所需要的签名密钥。这与Facebook、人人网等平台稍微有所区别,这两个平台在做参数签名时所用的签名密钥一般有2个:

  • 如果是通过应用服务端调用Open
    API,则注册应用时所拿到的应用密钥(即API Key)就是参数签名密钥;
  • 如果是通过JavaScript、ActionScript等客户端语言调用Open
    API,则应用获取到用户授权后所拿到的Session
    Secret就是参数签名密钥。当然,通过服务端调用Open
    API时也可以用Session Secret作为签名密钥。

在这之前,我们已经覆盖了包含Facebook、Twitter、Google
plus以及Instagram的Oauth登录系统示例。很遗憾之前我遗漏掉了Google的Oauth登录系统。今天我们就来看一下如何为你的web项目实现Google的Oauth系统。

 

签名算法

假设参与参数签名计算的请求参数分别是“k1”、“k2”、“k3”,它们的值分别是“v1”、“v2”、“v3”,则参数签名计算方法如下:

  • 将请求参数格式化为“key=value”格式,即“k1=v1”、“k2=v2”、“k3=v3”;
  • 将格式化好的参数键值对以字典序升序排列后,拼接在一起,即“k1=v1k2=v2k3=v3”;
  • 在拼接好的字符串末尾追加上应用通过百度OAuth2.0协议获取Access
    Token时所获取到的session_secret参数值;
  • 上述字符串的MD5值即为签名的值。

注意:计算签名时的请求参数中不要包含sign(签名)参数,因为sign参数的值此时还不知道,有待计算

另外,计算签名的时候不需要对参数进行urlencode处理(“application/x-www-form-urlencoded”编码),但是发送请求的时候需要进行urlencode处理,这是很多开发者最容易犯错的地方。

在这之前,我们已经覆盖了包含Facebook、Twitter、Google
plus以及Instagram的Oauth登录系统示例。很遗憾之前我遗漏掉了Google的Oauth登录系统。今天我们就来看一下如何为你的web项目实现Google的Oauth系统。这个示例脚本非常快,对增加你的web项目注册当然是很有帮助的。

How

我写作风格简洁,会用到一些技术词。

免责声明:本文档不作为包含所有认证方法的网络的目录;
本文档也不旨在提供“最佳”认证方法。
没人给钱贿赂我。
如果你想赞助我那更棒, 可以用一些其它方式,
比如领养一只小狗,或者帮助正在辛劳的人们。

引文:这些引文表示我引用的来源。
如果你想让我收下链接/更好地引用我的来源(不仅仅是一个链接到原始发布),我可以这样做。
如果你想让我更好的引用引文, 我当然愿意,不过请先让我知道<3。

遗漏,错误:
犯错并不罕见,我并不是安全方面的专家
如果你看到一些可以改进的东西请PR,告诉我哪里弄错了,我可以改进。
有关PR更多的信息,请查看CONTRIBUTIONS.md。

签名过程示例

假设某个应用需要获取某个uid为67411167的用户的基本资料,应用在之前的通过百度OAuth2.0服务获取Access
Token的过程中所拿到的session_key和session_secret参数值分别为:

  • session_key: “9XNNXe66zOlSassjSKD5gry9BiN61IUEi8IpJmjBwvU07RXP0J3c4GnhZR3GKhMHa1A=”
  • session_secret: “27e1be4fdcaa83d7f61c489994ff6ed6”

调用Open API时的系统时间(PHP中可以通过date(‘Y-m-d
H:i:s’)来获取当前系统时间)为”2011-06-21
17:18:09″,希望REST服务器以JSON格式返回调用结果,即相当于参与参数签名计算的请求参数集合为:

[
    "session_key" => "9XNNXe66zOlSassjSKD5gry9BiN61IUEi8IpJmjBwvU07RXP0J3c4GnhZR3GKhMHa1A=",
    "timestamp" => "2011-06-21 17:18:09",
    "format" => "json",
    "uid" => 67411167
]

 

则计算签名的具体过程如下:

  • 将请求参数格式化为“key=value”格式,格式化后的请求参数集合为:

    [

    "session_key=9XNNXe66zOlSassjSKD5gry9BiN61IUEi8IpJmjBwvU07RXP0J3c4GnhZR3GKhMHa1A=",
    "timestamp=2011-06-21 17:18:09",
    "format=json",
    "uid=67411167"
    

    ]

     

  • 将格式化好的参数键值对以字典序升序排列,得到如下参数集:

    [

    "format=json",
    "session_key=9XNNXe66zOlSassjSKD5gry9BiN61IUEi8IpJmjBwvU07RXP0J3c4GnhZR3GKhMHa1A=",
    "timestamp=2011-06-21 17:18:09",
    "uid=67411167"
    

    ]

     

  • 将前面排序好的参数集拼接在一起,得到如下字符串:

format=jsonsession_key=9XNNXe66zOlSassjSKD5gry9BiN61IUEi8IpJmjBwvU07RXP0J3c4GnhZR3GKhMHa1A=timestamp=2011-06-21 17:18:09uid=67411167
  • 在拼接好的字符串末尾追加上应用通过百度OAuth2.0协议获取Access
    Token时所获取到的session_secret参数值,得到如下字符串:

format=jsonsession_key=9XNNXe66zOlSassjSKD5gry9BiN61IUEi8IpJmjBwvU07RXP0J3c4GnhZR3GKhMHa1A=timestamp=2011-06-21 17:18:09uid=6741116727e1be4fdcaa83d7f61c489994ff6ed6
  • 对前面得到的字符串求MD5签名,得到的d24dd357a95a2579c410b3a92495f009就是调用API时所需要的sign参数值。

接下来便可以通过HTTP POST方法或HTTP GET方法请求百度Open
API的REST服务器,进行接口调用了,如:

GET /rest/2.0/passport/users/getInfo?session_key=9XNNXe66zOlSassjSKD5gry9BiN61IUEi8IpJmjBwvU07RXP0J3c4GnhZR3GKhMHa1A%3D&timestamp=2011-06-21+17%3A18%3A09&format=json&uid=67411167&sign=d24dd357a95a2579c410b3a92495f009 HTTP/1.1
Host: openapi.baidu.com
User-Agent: Client of Baidu Open Platform
Accept: */*
Accept-Encoding: gzip,deflate
Accept-Charset: utf-8
Connection: close

或
POST /rest/2.0/passport/users/getInfo HTTP/1.1
Host: openapi.baidu.com
User-Agent: Client of Baidu Open Platform
Accept: */*
Accept-Encoding: gzip,deflate
Accept-Charset: utf-8
Content-Length: 179
Connection: close

session_key=9XNNXe66zOlSassjSKD5gry9BiN61IUEi8IpJmjBwvU07RXP0J3c4GnhZR3GKhMHa1A%3D&timestamp=2011-06-21+17%3A18%3A09&format=json&uid=67411167&sign=d24dd357a95a2579c410b3a92495f009

 

澳门新浦京电子游戏 1

假想案例

我将使用本文档中的一个常见示例来说明在“客户端”(用户在其计算机前面)和“服务器”(后台)上发生的情况的登录流程。

我们的例子将会有一个想象的朋友:Beorn。
Beorn喜欢针织,经常去http://knittingworld.com购买用品。
Beorn在knittingworld有一个帐号,我们将看到他登陆的例子。

签名算法实现代码

Google Oauth登录系统开发示例

一般最佳做法

在讨论用于管理身份验证的技术之前,以下是你不应该做的。

以下某些项目可能不直接与登录/身份验证/用户注册有关,但通常有用。

  • 切勿将密码存储为数据库中的纯文本。

  • 不要写自己的哈希算法(除非你真的很聪明)

  • 不要写自己的认证技术(再次,除非你真的很聪明)。

  • 使用HTTPS。

一些忠告

我们还发现许多网站设计自己的身份验证机制,以提供更好的用户体验。不幸的是,设计师和实现者通常没有安全背景,因此不能很好地理解他们可以使用的工具[2]

PHP代码实现

获取签名的PHP代码实现方式如下所示:

/**
  * 签名生成算法
  * @param  array  $params API调用的请求参数集合的关联数组,不包含sign参数
  * @param  string $secret 签名的密钥即获取access token时返回的session secret
  * @return string 返回参数签名值
  */
 function getSignature($params, $secret)
 {
    $str = '';  //待签名字符串
    //先将参数以其参数名的字典序升序进行排序
    ksort($params);
    //遍历排序后的参数数组中的每一个key/value对
    foreach ($params as $k => $v) {
        //为key/value对生成一个key=value格式的字符串,并拼接到待签名字符串后面
        $str .= "$k=$v";
    }
    //将签名密钥拼接到签名字符串最后面
    $str .= $secret;
    //通过md5算法为签名字符串生成一个md5签名,该签名就是我们要追加的sign参数值
    return md5($str);
 }

 

调用示例:

$uid = 67411167;
$params = array(
    "session_key" => "9XNNXe66zOlSassjSKD5gry9BiN61IUEi8IpJmjBwvU07RXP0J3c4GnhZR3GKhMHa1A=",
    "timestamp" => "2011-06-21 17:18:09",
    "format" => "json",
    "uid" => $uid,
);
$sign = getSignature($params, "27e1be4fdcaa83d7f61c489994ff6ed6");

 

数据库设计

术语

web验证开发领域中有相当多的术语。下面是一个术语列表,您将在下面看到。

Java代码实现

获取签名的java代码实现方式如下所示:

/**
 * 签名生成算法
 * @param HashMap<String,String> params 请求参数集,所有参数必须已转换为字符串类型
 * @param String secret 签名密钥
 * @return 签名
 * @throws IOException
 */
public static String getSignature(HashMap<String,String> params, String secret) throws IOException
{
    // 先将参数以其参数名的字典序升序进行排序
    Map<String, String> sortedParams = new TreeMap<String, String>(params);
    Set<Entry<String, String>> entrys = sortedParams.entrySet();

    // 遍历排序后的字典,将所有参数按"key=value"格式拼接在一起
    StringBuilder basestring = new StringBuilder();
    for (Entry<String, String> param : entrys) {
        basestring.append(param.getKey()).append("=").append(param.getValue());
    }
    basestring.append(secret);

    // 使用MD5对待签名串求签
    byte[] bytes = null;
    try {
        MessageDigest md5 = MessageDigest.getInstance("MD5");
        bytes = md5.digest(basestring.toString().getBytes("UTF-8"));
    } catch (GeneralSecurityException ex) {
        throw new IOException(ex);
    }

    // 将MD5输出的二进制结果转换为小写的十六进制
    StringBuilder sign = new StringBuilder();
    for (int i = 0; i < bytes.length; i++) {
        String hex = Integer.toHexString(bytes[i] & 0xFF);
        if (hex.length() == 1) {
            sign.append("0");
        }
        sign.append(hex);
    }
    return sign.toString();
}

 

注意:计算签名时所有参数的key和value都必须先转换为对应的字符串类型,因为在HTTP请求中传递的内容都是字符串类型的,很多开发者都因为没注意到这点,直接将非字符串类型的参数的二进制值传递了进去,结果导致签名与服务端计算的不一致而出错。

数据库设计很简单,如下所示:

HTTP 超文本传输协议。

这是一个大的概念。我只能简单的解释一下它的含义。Web是围绕HTTP构建的 –
它是用于在Web服务器和用户之间通信的协议。

您的浏览器被视为HTTP客户端,因为它向HTTP服务器发送请求。你的客户可以做很多不同类型的请求,

  • 你可能听说过一些最流行的请求 – POST POST PUT和DELETE。

HTTP服务器向您的浏览器 – 客户端发送响应。
这些响应就是资源。
资源可以是(但不限于):HTML文件,图像,文本,JSON等。
你可以认为资源是从服务器返回的“文件”。

关于此主题的其他链接:

  • HTTP Made Really Easy

  • RFC2616 –
    这是一个关于HTTP的文档规范。
    它被列为过期,但也列出了取代它的文档。

C#代码实现

获取签名的C#代码实现方式如下所示:

/// <summary>
/// 计算参数签名
/// </summary>
/// <param name="params">请求参数集,所有参数必须已转换为字符串类型</param>
/// <param name="secret">签名密钥</param>
/// <returns>签名</returns>
public static string getSignature(IDictionary<string, string> parameters, string secret)
{
    // 先将参数以其参数名的字典序升序进行排序
    IDictionary<string, string> sortedParams = new SortedDictionary<string, string>(parameters);
    IEnumerator<KeyValuePair<string, string>> iterator= sortedParams.GetEnumerator();

    // 遍历排序后的字典,将所有参数按"key=value"格式拼接在一起
    StringBuilder basestring= new StringBuilder();
    while (iterator.MoveNext()) {
            string key = iterator.Current.Key;
            string value = iterator.Current.Value;
            if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(value)){
                basestring.Append(key).Append("=").Append(value);
            }
    }
    basestring.Append(secret);

    // 使用MD5对待签名串求签
    MD5 md5 = MD5.Create();
    byte[] bytes = md5.ComputeHash(Encoding.UTF8.GetBytes(basestring.ToString()));

    // 将MD5输出的二进制结果转换为小写的十六进制
    StringBuilder result = new StringBuilder();
    for (int i = 0; i < bytes.Length; i++) {
            string hex = bytes[i].ToString("x");
            if (hex.Length == 1) {
                result.Append("0");
            }
            result.Append(hex);
    }

    return result.ToString();
}

 

注意:计算签名时所有参数的key和value都必须先转换为对应的字符串类型,因为在HTTP请求中传递的内容都是字符串类型的,很多开发者都因为没注意到这点,直接将非字符串类型的参数的二进制值传递了进去,结果导致签名与服务端计算的不一致而出错。

CREATE TABLE users  
(  
id INT PRIMARY KEY AUTO_INCREMENT,  
email VARCHAR(50) UNIQUE,  
fullname VARCHAR(100),  
firstname VARCHAR(50),  
lastname VARCHAR(50),  
google_id VARCHAR(50),  
gender VARCHAR(10),  
dob VARCHAR(15),  
profile_image TEXT,  
gpluslink TEXT

HTTPS

HTTPS是安全的HTTP。
它与SSL / TLS密切相关。
最初在互联网上的支付交易很受欢迎,最近变得越来越普遍。
您可能会认为https是“在浏览器中显示在我的网址左侧的绿色文本”;
经常伴随着锁的图标或类似的东西。

HTTPS是用TLS(或在过去的日子里,SSL)封装的HTTP,以保护浏览器和服务器之间的流量。

HTTPS会对与您的HTTP请求一起发送的信息和发回的响应进行加密。这在我们开始谈论身份验证时尤其重要!

来自维基百科:

HTTPS在不安全的网络创建安全通道。

这确保了合理的保护免受窃听者和中间人攻击,只要使用足够的密码套件并且服务器证书被验证和信任。

1,域名注册

TLS / SSL

TLS和SSL是加密协议。
TLS和SSL加密您通过网络发送的数据 –
它旨在防止人们“窃听”或篡改您要发送的数据。
SSLv2和v3今天被视为不安全(请参阅POODLE),因此大多数HTTPS是使用TLS
1.2完成的。
YouTube上有一些有用的视频,有助于解释这些复杂的问题,
这个视频MIT
opencourseware挺不错的!

在这里注册或者添加你的域名。

State

statestatefulstatelesspiece of state
这些是术语,它们的定义不同。
在本文里,“piece of state”或“stateful”描述了一块存储在内存中的数据。

HTTP请求通常被描述为“stateless”。
当您访问网站和登录时,您正在传递一些信息以及您的HTTP请求,
用来标识您的身份。

澳门新浦京电子游戏 2

无论你需要使用什么身份验证方法来识别自己,都必须“附加”到某个或另一个HTTP请求,因为你不能简单地将该状态放在HTTP协议本身中

必须采取另一种形式,可以凌驾于HTTP协议之上(正如你会看到在本文档的其余部分。)。
可能有点夸张… 我认为这篇来自苏格兰的文章解释的很不错The Ins and Outs
of Token Based
Authentication。

由于HTTP协议是无状态的,这意味着如果我们使用用户名和密码验证用户,那么在下一个请求,我们的应用程序将不知道我们是谁。我们必须再次验证。

域名注册

Cookies

Cookie是存储在用户浏览器上的小数据。Cookie与HTTP相反,是有状态的 –
这意味着尽管HTTP不能存储用户信息,但是cookie可以。

网络Cookie的常见示例:

Beorn访问http://knittingworld.com为他的下一个针织项目购买一些不错的纱线和材料。
他登录后向他的购物车添加了三件商品。突然他听到一声砰!
并意识到他的微波炉里还有一罐金枪鱼。不好!
Beorn关闭了浏览器,立即忘记了他购物车里的东西,跑去检查微波炉。
罐头金枪鱼的酱汁已经洒在他家的地板上,Beorn回到他的电脑前,并重新访问https://knittingworld.com …想看看他之前加入购物车的商品还在不在。
Cookies。

有不同种类的Cookies。有些Cookie会在您的浏览器中停留多天,而其他Cookie会在您关闭浏览器后立即消失。

Cookie在过去(仍然是)认证中起到了很大的作用。Web服务器通常使用认证cookie来确定用户是否登录以及他们有权访问哪些资源。

持久性cookie有时会带来麻烦,因为它们可以被广告商用来记录关于用户的web习惯的信息。
另一方面,它们通常用于保存用户每次访问站点时不必重新输入其登录凭证。

您可以通过导航到您的(使用Chrome)开发者工具并打开网络标签查看与请求一起发送的Cookie。
刷新页面将显示传入资源的列表,您可以选择其中的一个。
滚动列表, 看看找得到cookie不!
您也可以在开发人员工具的[Application]标签中查看Cookie 的相关信息。

2,所有权认证

Sessions / Session Management

我并不会一开始就去尝试简单的描绘出sessions,我会引用OWASP:

网络会话是与同一用户相关联的网络HTTP请求和响应事务的序列。

现代和复杂的web应用程序需要在多个请求期间保留关于每个用户的信息或状态。因此,会话提供了建立变量的能力,例如访问权限和本地化设置,这将适用于在会话期间用户与webApp的每一次交互。

您可以在下面的“Methodologies”部分找到基于会话身份验证的示例。关于Sessions的更多链接:

  • How does a web session
    work

  • What are web
    sessions?

验证您的域名所有权,可以通过HTML文件上传或包括META标记。

Methodologies

以下是用于建立认证的技术方案列表。这不是一个完整的列表!

澳门新浦京电子游戏 3

HTTP基本认证

HTTP基本身份验证(或“基本身份验证”)已经存在了很长时间。看起来人们倾向于使用它,因为它的简单性,它支持跨浏览器。这是一个空白页面,要求基本的验证。这里将演示如何确保webApp正常运行当Beorn关闭游览器重新再打开后:

  • Beorn去http://knittingworld.com 买纱线。

  • 在挑选出纱线后,他点击“购买”按钮购买。

  • 他的浏览器发出一个GET请求,服务器响应401告诉他需要验证。

  • Beorn在他的用户名和密码中输入登录表单。

  • 在他点击登陆后,他的浏览器会发起GET(POST)请求,
    并在请求头里带着Authorization。Authorization请求头类似于这样Authorization:QWxhZGRpbjpvcGVuIHNlc2FtZQ==

  • 服务器继续验证身份验证头并确定Beorn是否可以可以提交购买操作。浏览器会记住Authorization,之后的每一次游览器提交的请求,都会在请求头里加上Authorization:QWxhZGRpbjpvcGVuIHNlc2FtZQ==
    直到游览器关闭。

所有权认证

关于HTTP基本身份验证的一些重要注意事项:

  • 上面的示例授权头部看起来不像用户名和密码,但是这是因为它是base64编码。它没有加密。

  • 如果使用HTTP基本认证,请使用HTTPS。如果使用HTTP,身份验证凭据将作为明文发送到服务器。这不好。用户的用户名和密码通过线路仅作为base64编码文本发送 –
    这对于解码来说很简单。通过使用HTTPS /
    TLS,您确保从客户端发送到服务器的数据被加密。

  • HTTP基本验证由游览器实现,今天很少使用。

  • 基本验证使用API​​的基本认证,当与令牌组合时,(稍后讨论)只是一个授权报头,是完全合理的。它有额外的好处,不需要API客户端维护一个额外的会话cookie,并且,因为大多数系统日志查询参数而不是标题,将不会被默认记录。

  • 基本验证与Token组合的时候,
    好处很多,比如不需要客户端单独维护一个cookie,
    并且也不会被客户端记录。

3,OAuth Keys

链接

  • Basic Authentication on
    OWASP

  • Why does stripe use HTTP basic auth with a token instead of the
    header

谷歌将提供你OAuth用户密钥和OAuth秘密密钥。

基于Session的认证

Session认证已经存在了一段时间,并且平常用的比较多。基于session的身份验证的关键是,用户的登录与服务器上的内存的一段状态或key-value存储(如Redis中)相关联。

让我们看看我们的朋友Beorn使用基于session的身份验证的示例。

  • Beorn去http://knittingworld.com 买一些东西。

  • 当Beorn登录时,他将他的凭据发送到服务器。

  • 当凭据到达服务器时,服务器以这种方式或另一种方式需要检查Beorn是否是其数据库中的用户。在这一点上,Beorn还没有登录。

  • Beorn的凭据匹配成功,所以他可以登录。

  • Beorn需要一些东西来识别他对服务器的未来请求 –
    特别是如果他想要购买东西(必须登陆才能买)。这就是认证session的思想。

  • 现在服务器知道Beorn是谁,并且已经将他识别为数据库中的用户,服务器将向他(或“返回”)发送一个cookie,这可以将Beorn列为在以后的请求中是已经登陆的用户。

  • 现在,Beorn已经验证,并在他的浏览器上有一个session
    cookie(cookie的一种)。

  • 当Beorn转到页面 他正在做另一个HTTP请求 –
    但这次,他的session cookie将放在HTTP请求头里发送到服务器。

  • 服务器将根据与内存中Session信息匹配的cookie进行身份验证(可以用redis,memcache等数据库来保存)

  • 当Beorn从http://knittingworld.com 退出时,他在服务器(或Redis等)上的会话实例将过期,他的会话cookie也会过期。

澳门新浦京电子游戏 4

基于Token的认证

基于令牌的认证已经变得更加普遍最近随着RESTful
API的应用,单页应用程序和微服务的兴起。

Oauth keys

什么是token?

token是一小块数据。

利用基于Token的认证的认证系统意味着用户向服务器发出的请求携带token以执行认证逻辑。当发出HTTP请求时,
token是验证用户是否有资格访问资源的凭证。

4, Google API控制台

这与基于Cookie的身份验证有何不同?

token认证是无状态的,而基于session的认证意味着在您的服务器(或在Redis等)中的某个地方保存着状态用以识别用户。

Auth0的博客文章Cookies vs Tokens:The
Definitive 描述了cookie和令牌之间的身份验证流程的差别的:

在Google
API控制台创建客户端ID。

基于session的认证流程:

1. 用户输入其登录信息
2. 服务器验证信息是否正确,并创建一个session,然后将其存储在数据库中
3. 具有sessionID的Cookie将放置在用户浏览器中
4. 在后续请求中,会根据数据库验证sessionID,如果有效,则接受请求
5. 一旦用户注销应用程序,会话将在客户端和服务器端都被销毁

澳门新浦京电子游戏 5

基于令牌的认证流程:

1. 用户输入其登录信息
2. 服务器验证信息是否正确,并返回已签名的token
3. token储在客户端,最常见的是存储在`local storage`中,但也可以存储在session存储或cookie中
4. 之后的HTTP请求都将token添加到请求头里
5. 服务器解码JWT,并且如果令牌有效,则接受请求
6. 一旦用户注销,令牌将在客户端被销毁,不需要与服务器进行交互一个关键是,令牌是无状态的。后端服务器不需要保存令牌或当前session的记录。

Google API控制台

哇标记听起来很酷。他们比基于session的身份验证更好吗?

问错人了,伙计。我只是告诉你存在这个验证方式。我不会比较没有意义的比较,我尽最大努力做到这一点。有关更多有趣的免责声明,请访问上面的免责声明部分。令牌的类型一些常见的令牌包括JWT(下面讨论),SWT(简单网络令牌)和SAML(安全断言标记语言)

澳门新浦京电子游戏 6

链接

  • Token Based Authentication – Implemenation Demonstration –
    W3

  • What is token based Authentication –
    SO

  • Token Based Authentication Made
    Easy

  • The Ins and Outs of Token Based
    Authentication

  • Cookies vs Tokens: The Definitive Guide
    (opinionated)

Google API控制台

JWT

JWT代表“JSON Web Token”。
JWT是一种基于Token的认证。
JWT基于Web标准。现在JWT用的越来越多;JWT是Token认证的一种,所以说JWT基于Token的认证。再次,基于Token的认证的不同方法具有不同的优点和缺点。因此,上面的基于令牌的认证部分中的很多信息适用于此。

来自JWT RFC 7519标准化的摘要说明:JSON Web
Token(JWT)是一种紧凑的,URL安全的方式,表示要在双方之间传输的声明。

JSON Web令牌是一个字符串。它可能看起来像这样:

eyJhbGciOIJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

上面的字符串是你在使用JWT执行身份验证时可能看到的;它是在认证时从服务器返回的凭证。JWT经过验证并且安全,因为它们使用私钥进行“数字签名”,并使用密钥进行身份验证。

然后你就可以看见你的客户端ID和密钥。

JWT的结构?

JWT是一个自包含的数据块。每个JWT由payloadsignature组成。当您的服务器创建token时,您还可以为token分配唯一的数据,可以在前端使用。这可以用于保存稍后进行其他数据库调用的需要。你仍然应该警惕在发送给客户的令牌中发布机密信息(比如说用户密码等等)。

澳门新浦京电子游戏 7

在Python中创建JWT令牌的示例函数:

def create_token(user):
    """Create a JWT token, set expiry, iat, etc"""
    payload = {
        'sub': user.id,
        'name': user.first_name,
        'role_id': user.role_id,
        'iat': datetime.utcnow(),
        'exp': datetime.utcnow() + timedelta(days=1)
    }
    token = jwt.encode(payload, MY_SECRET_KEY_SHHH_DONT_TELL_ANYONE, algorithm='HS256')
    return token.decode('unicode_escape')

上面的键sub,iat和exp跟随保留的JWT键,但我也添加了用户的名称和role_id。你将需要一个库来编码/解码JWT令牌。 JWT.io列出了许多语言的库。

配置好的Google Oauth信息

链接w

  • Introduction to JSON web tokens

  • JWT Debugger

config.php

OAuth

OAuth是一种认证协议,允许用户对没有密码的服务器执行认证。
OAuth存在很多版本 – OAuth 1.0,OAuth 1.0a和OAuth 2.0。

如果您曾使用Twitter,Google或Facebook帐户登录了某项服务,那么您已使用OAuth。

OAuth提供商(Facebook,Google等)通过提供您的服务(“OAuth客户端”)身份验证方式的私有,唯一的访问令牌,允许登录。

如果您要使用OAuth让用户登录您的服务,则需要将您的服务器注册为OAuth客户端。这通常会设置一个客户端ID和客户端密钥。登录到您的服务的用户将重定位到OAuth提供程序,用户可以在其中确认他们确实想要“登录”(即允许他们登录的服务器)访问OAuth提供程序的任何必需的信息。
)在我们的朋友Beorn的情况下…

在我们的朋友Beorn的情况下…

  • Beorn去http://knittingworld.com 买东西。

  • Beorn决定使用他的Google帐户登录。

  • 提示Beorn输入他的google帐户信息(如果他还没有登录

  • 输入信息后,Google(或者其它的OAuth提供商)将提示他是否要使用他的Google帐户登录http://knittinggworld.com 。

  • 接受后,Beorn被重定向到http://knittingworld.com 。

  • 如果knittingworld需要访问关于Beorn信息的资源,它可以向资源服务器(通过OAuth提供者)请求访问它们,只要它的token是有效的。

OWASP说:

建议使用OAuth
1.0a或OAuth
2.0,因为已发现第一个版本(OAuth1.0)容易受到session固定的影响。OAuth
2.0依靠HTTPS进行安全保障,目前OAuth的API(如Facebook,Google,Twitter和Microsoft)已经实现了。
OAuth1.0a很难使用,因为它需要使用用于数字签名的加密库。然而,由于OAuth1.0a不依赖HTTPS来实现安全性,因此它更适合于更高风险的事务。

你可以在src文件夹找到这个文件,在这里您需要配置应用程序OAuth密钥,Consumer
keys和重定向回调URL。

链接

  • A Fun explanation of OAuth involving
    Donuts
// OAuth2 Settings, you can get these keys at https://code.google.com/apis/console Step 6 keys  
'oauth2_client_id' => 'App Client ID',  
'oauth2_client_secret' => 'App Client Secret',  
'oauth2_redirect_uri' => 'http://yoursite.com/gplus/index.php',  

// OAuth1 Settings Step 3  keys.  
'oauth_consumer_key' => 'OAuth Consumer Key',  
'oauth_consumer_secret' => 'OAuth Consumer Secret',

OpenId

OpenId是另一种不需要密码的身份验证协议(类似于OAuth)。
OpenId网站有一个非常简洁明了的描述,在我看来:

OpenID允许您使用现有帐户登录多个网站,而无需创建新密码。您可以选择将信息与您的OpenID相关联,以便与您访问的网站(例如姓名或电子邮件地址)共享。使用OpenID,您可以控制与您访问的网站共享的信息量。使用OpenID,您的密码仅提供给您的身份提供商,然后该提供商会确认您访问的网站的身份。除了您的提供商,没有网站曾经看到您的密码,因此您不需要担心一个不道德或不安全的网站危害您的身份。

虽然从2005年开始,最近(2014年-h),OpenId发布了OpenId
Connect,这是一种“基于OAuth 2.0系列规范的可互操作身份验证协议”(源)

google_login.php

OpenId和OAuth有什么区别?

OpenId类似于OAuth,但有一些差异。类似地,OpenId依赖于与第三方(依赖方(您登录的站点))交互以提供认证凭证的身份提供商。

不同的是,您可以使用OAuth允许您登录的网站能够访问来自提供程序的数据。这听起来可怕和混乱,但这里有一个简单的例子:

  • Beorn注册为twitter。他要推销他编织的帽子

  • Beorn不知道follow谁,没有人follow他。 Beorn悲伤的感觉不重要。

  • Twitter提示Beorn使用OAuth连接他的Google帐户,以便他可以导入他的联系人到Twiiter。

  • Beorn follow了一群人,包括来自他多年没有见过的高中的老朋友

  • Beorn这样做了,现在他正在不停地tweeting。

Google plus登录系统,你只需要在index.php中加载这个文件。

<?php  
require_once 'src/apiClient.php';  
require_once 'src/contrib/apiOauth2Service.php';  
session_start();  
$client = new apiClient();  
setApplicationName("Google Account Login");  
$oauth2 = new apiOauth2Service($client);  
if (isset($_GET['code']))  
{  
$client->authenticate();  
$_SESSION['token'] = $client->getAccessToken();  
$redirect = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];  
header('Location: ' . filter_var($redirect, FILTER_SANITIZE_URL));  
}  
if (isset($_SESSION['token'])) {  
$client->setAccessToken($_SESSION['token']);  
}  
if (isset($_REQUEST['logout'])) {  
unset($_SESSION['token']);  
unset($_SESSION['google_data']); //Google session data unset  
$client->revokeToken();  
}  
if ($client->getAccessToken())  
{  
$user = $oauth2->userinfo->get();  
$_SESSION['google_data']=$user; // Storing Google User Data in Session  
header("location: home.php");  
$_SESSION['token'] = $client->getAccessToken();  
} else {  
$authUrl = $client->createAuthUrl();  
}  
if(isset($personMarkup)):  
print $personMarkup;  
endif 
if(isset($authUrl))  
{  
echo "<a class="login" href="$authUrl">Google Account Login</a>";  
} else {  
echo "<a class="logout" href="?logout">Logout</a>";  
}  
?>

home.php

在这里我们需要向之前创建的user表插入Google plus的session信息。代码如下:

<?php  
session_start();  
include('db.php'); //Database Connection.  
if (!isset($_SESSION['google_data'])) {  
// Redirection to application home page.  
header("location: index.php");  
}  
else 
{  
//echo print_r($userdata);  
$userdata=$_SESSION['google_data'];  
$email =$userdata['email'];  
$googleid =$userdata['id'];  
$fullName =$userdata['name'];  
$firstName=$userdata['given_name'];  
$lastName=$userdata['family_name'];  
$gplusURL=$userdata['link'];  
$avatar=$userdata['picture'];  
$gender=$userdata['gender'];  
$dob=$userdata['birthday'];  
//Execture query  
$sql=mysql_query("insert into users(email,fullname,firstname,lastname,google_id,gender,dob,profile_image,gpluslink) values('$email','$fullName','$firstName','$lastName','$googleid','$gender','$dob','$avatar','$gplusURL')");  
?>

db.php

数据库配置文件。

<?php  
$mysql_hostname = "localhost";  
$mysql_user = "username";  
$mysql_password = "password";  
$mysql_database = "databasename";  
$bd = mysql_connect($mysql_hostname, $mysql_user, $mysql_password) or die("Could not connect database");  
mysql_select_db($mysql_database, $bd) or die("Could not select database");  
?>

发表评论

电子邮件地址不会被公开。 必填项已用*标注