主页

oAuth

2021-08-20
java

  • oAuth是一种授权机制,数据所有者告诉授权系统,允许第三方应用获取这些数据,授权系统从而产生一个短期的进入令牌(token),第三方应用通过令牌获取数据。

授权码方式 #

第三方应用(记为a)访问CALLBACK_URL这个网站,会重定向到授权系统(记为b),url如1所示

1. 请求授权码 #

https://b.com/oauth/authorize?
  response_type=code& #表示参数要求返回授权码
  client_id=CLIENT_ID& #客户端idb就知道是谁在请求
  redirect_uri=CALLBACK_URL& #b接收请求后跳转的网站
  scope=read #授权范围

2. 返回授权码 #

在授权系统登录成功后,会重定向到CALLBACK_URL?code=AUTHORIZATION_CODE,code就是授权码。

3. 请求令牌 #

CALLBACK_URL这个网站会重定向到授权系统,url如下:

https://b.com/oauth/token?
 client_id=CLIENT_ID& #客户端idb就知道是谁在请求
 client_secret=CLIENT_SECRET& 
 grant_type=authorization_code& #授权类型,表明是授权码
 code=AUTHORIZATION_CODE& #上一步拿到的授权码
 redirect_uri=CALLBACK_URL #b之后跳转的网站

4. 返回令牌 #

授权系统会重定向到CALLBACK_URL,并发送一段JSON数据

{  
  "access_token":"ACCESS_TOKEN(令牌)",  
  "token_type":"bearer",
  "expires_in":2592000,
  "refresh_token":"REFRESH_TOKEN",
  "scope":"read",
  "uid":100101,
  "info":{...}
}

参考链接: OAuth 2.0 的四种方式 - 阮一峰的网络日志 (ruanyifeng.com)

https

2021-08-20
http

  • 如何保证公钥不被篡改?将公钥放在数字证书中,只要证书是可信的,公钥就是可信的。

握手过程 #

  • 涉及四次通信。

1. 客户端发送请求(ClientHello)。 #

客户端向服务器提供以下信息:

  1. 支持的协议版本,如TLS1.0版本。
  2. 客户端生成的随机数,是之后生成会话密钥的一部分。
  3. 支持的加密算法,如RSA。
  4. 支持的压缩算法。

2. 服务器收到请求后,向客户端发出回应(ServerHello)。 #

服务器向客户端发出回应包含以下内容(如果服务器需要确认客户端的身份,就需要再包含一项请求,要求和护短提供证书文件):

  1. 确认使用的协议版本。
  2. 服务器生成的随机数,是之后生成会话密钥的一部分。
  3. 确认使用的加密算法。
  4. 服务器证书。

3. 客户端回应 #

客户端收到回应后,先验证服务器的证书,如果证书不是可信机构颁发、证书中的域名与实际域名不一致、证书已经过期,就会显示一个警告询问是否继续。如果继续或者证书没有问题,客户端向服务端发送以下内容:

  1. 一个随机数(pre-master key),该随机数用服务器的公钥加密。
  2. 编码改变通知,表示随后的信息都用协商的加密算法和密钥发送。
  3. 客户端的握手结束通知,包含前面发送所有内容的hash值,供服务器校验。

4. 服务器回应 #

服务器收到第三个随机数后,计算会话使用的“会话密钥”,向客户端发送以下信息:

  1. 编码改变通知,表面之后的信息都用协商的加密算法和密钥发送。
  2. 服务器握手状态结束通知,包含签名发送的所有内容的hash值。

  • 中间人攻击:如果中间人在客户端与服务端开始建立连接的时候,拦截客户端的请求,让客户端与自己通信,自己再和服务端通信,出现了:客户端请求->中间人->服务端,服务端响应->中间人->客户端,中间人能获取到客户端请求的所有数据和服务端响应的所有数据。所以当出现证书不安全的时候要注意。

参考链接: SSL/TLS协议运行机制的概述 - 阮一峰的网络日志 (ruanyifeng.com)

jwt协议

2021-08-20
java

  • 全称是JSON Web Token。
  • jwt由下面三个部分组成,格式类似aaa.bbb.ccc
    • Header(头部)
    • Payload(负载)
    • Signature(签名)

  • Header部分是一个JSON对象,由签名算法和token类型组成,会使用用Base64URL加密,加密后的数据组成jwt的第一部分。原始数据如下(例):
{
    "alg":"HS256",
    "typ":"JWT"
}
  • Payload也是一个JSON对象,会用Base64URL加密,加密后的数据组成jwt的第二部分。默认定义了一些参数 iss(ssuer):签发人,exp(expiration):过期时间,sub(subject):主题,aud(audience):受众,nbf(not before):生效时间,iat(issued at):签发时间,jti(jwi id):编号。原始数据如下(例):
{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}
  • Signature会根据服务端的密钥和Header中给的算法,对加密后的Header和加密后的Payload再次进行加密,将加密的结果组成jwt的第三部分。加密的逻辑如下:
HMACSHA256( base64UrlEncode(header) + '.' + base64UrlEncode(payload), secret)

  • 可以在HTTP的headers中的使用,这样就不会有跨域问题了(因为没有使用cookie):
Authorization:Bearer <token>

参考链接: JSON Web Token Introduction - jwt.io 参考链接: JSON Web Token 入门教程 - 阮一峰的网络日志 (ruanyifeng.com) 解密jwt: JSON Web Tokens - jwt.io

cas协议

2021-08-19
java

CAS详细流程

CAS协议 #

  • central authentication service(中央认证服务),TGT(Ticket Grangting Ticket)。TGC(ticket-granting cookie)、ST(service ticket)
  • 流程如下(所有的过程都是重定向):
  1. 用户通过浏览器访问业务系统(就是CAS client,可能是某个微服务)。
  2. 业务系统重定向到CAS server。
  3. server对用户进行认证,如用户提供了正确的认证信息,server就会创建对应的session(似乎就是TGT),TGC(cookie)是该session的key,server把TGT和生成的ST发给浏览器。
  4. 浏览器重新请求该业务系统,同时url上带上了ST=xxx访问业务系统。
  5. 业务系统拿到ST后,向Server发起校验,校验成功后生成session和cookie,将cookie发送给浏览器。
  6. 浏览器带上该cookie,不带ST向业务系统发出请求。
  7. 业务系统验证cookie成功,系统登录成功。

参考链接: CAS - CAS Protocol (apereo.github.io)

rest

2021-08-19
http

  • POST:创建,PUT:修改,DELETE:删除,GET:获取

jpa

2021-08-18
java

jpa方法支持的关键字 #

关键字 例子 jpql
Distinct findDistinctByLastnameAndFirstname select distinct … where x.lastname=?1 and x.firstname=?2
And findByFirstnameAndLastname … where x.firstname=?1 and x.lastname=?2
Or findByFirstNameOrLastname … where x.firstname=?1 and x.lastname=?2
Is,Equals findByFirstname,findByFirstnameIs,findByFirstnameEquals … where x.firstname=?1
Between findByStartDateBetween … where x.startDate between ?1 and ?2
LessThan findByAgeLessThan … where x.age <?1
LessThanEqual findByAgeLessThanEqual … where x.age?=?1
GreaterThan findByAgeGreaterThan … where x.age>?1
After findByStartDateAfter … where x.startDate >?1
Before findByStartDateBefore … where x.startDate<?1
IsNull,Null findByAge(Is)Null … where x.age is null
IsNotNull,NotNull findByAge(Is)NotNull … where x.age not null
Like findByFirstnameLike … where x.firstname like?1
NotLike findByFirstnameNotLike … where x.firstname not like ?1
StartingWith findByFirstnameStartingWith … where x.firstname like ?1` (参数后面加%)
EndingWith findByFirstnameEndingWith … where x.firstname like ?1 (参数前面加%)
Containing findByFirstnameContaining … where x.firstname like ?1 (参数前后加%)
OrderBy findByAgeOrderByLastnameDesc … where x.age = ?1 order by x.lastname desc
Not findByLastnameNot … where x.lastname <> ?1
In findByAgeIn(Collection//<Age//> ages) … where x.age in ?1
NotIn findByAgeNotIn(Collection ages) … where x.age not in ?1
True findByActiveTrue … where x.active = true
False findByActiveFalse() … where x.active = false
IgnoreCase findByFirstnameIgnoreCase … where UPPER(x.firstname) = UPPER(?1)

ddl-auto #

  • none:禁用ddl;
  • validate:验证表结构,不对数据库有任何修改;
  • update:如果启动时表格式不一样则更新表,原有数据保留
  • create:启动时删除数据库中的表,然后创建;
  • create-drop:启动时删除数据库中的表,然后创建,退出时删除数据表。

http状态码

2021-08-17
http

消息响应 #

  • 101 Switching Protocol 表示正在切换协议。
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade

成功响应 #

  • 200 OK请求成功。
  • 201 CREATED请求已成功,通常是POST、PUT请求后返回的响应。

重定向 #

  • 301 MOVED PERMENENTLY请求的资源已经被永久移动到新位置。
  • 302 FOUND重定向是临时的。
  • 304 Not Modified 当文档内容没有修改,服务器会返回这个状态码,304响应禁止包含消息体。

客户端响应 #

  • 400 BAD REQUEST请求参数有误。
  • 401 UNAUTHORIZED当前请求需要用户验证。
  • 403 FORBIDDEN服务器已经理解请求,但是拒绝执行。
  • 404 NOT FOUND请求资源未找到。
  • 405 Method Not Allowed 请求方法不能被用于请求相应的资源。该响应必须返回一个Allow头用以表述当前资源能够接受的请求方法的列表。
  • 414 URI Too Long 请求的URI长度超过了服务器能够解释的长度,因此服务器拒绝对该请求提供服务。通常是因为超过了GET方法传输数据的上限,可以改为POST方法。

服务端响应 #

  • 500 INTERNAL SERVER ERROR服务器内部错误。
  • 502 BAD GATEWAY服务器作为网关需要得到处理该请求的响应,但得到了一个错误的响应。
  • 503 SERVICE UNAVILABLE服务器没有准备好处理请求。

参考链接: HTTP 响应代码 - HTTP | MDN (mozilla.org)

redis起步

2021-08-13
java

  • 支持string、list、set、有序set、hash等数据类型
  • 通过./redis-server [redis.conf] 启动服务。
  • 通过./redis-cli [-h hostname] [-p port] 连接redis,登录后通过AUTH password来输入密码。

命令 #

  • keys * 查看当前库中的所有key。
  • exists key 判断某个key是否存在
  • rename key newkey键重命名
  • type key 查看key是什么类型
  • del key 删除指定的key数据
  • expire key 10 给key设定10秒的过期时间
  • ttl key 查看还有多少秒过期,-1表示永不过期,-2表示已过期
  • select index 切换数据库,默认有16个库
  • dbsize 查看当前库key的数量
  • set key value 设置字符串类型的键值对
  • get key 获取值

数据类型 #

string #

  • set key value 设置值
  • get key 获取key对应的值
  • strlen key 获取值的长度。
  • mset key1 value1 key2 value2 同时设置多个键值对。
  • mget key1 key2 同时获取多个键值对。
  • append key value 将给定的value追加到原值的末尾。
  • setnx key value 只有当key不存在的时候才设置key的值。
  • incr key key的值加一。
  • decr key key的值减一。
  • incrby key 步长 key的值加步长。
  • decrby key 步长 key的值减步长。
  • msetnx key1 value1 key2 value2 同时设置多个键值对,当有一个key存在的时候,所有的设置都会失败。
  • setex key seconds value 设置键值对的同时设置过期时间,单位是秒。
  • String内部采用类似arraylist的机制,字符串实际分配的空间一般高于字符串的长度,当字符串长度小于1M时,扩容都是加倍的,超过1M时,每次扩容都是只增加1M。最大为512M。

链表 #

节点的结构 #

//adlist.h/listNode
//结构
typedef struct listNode {
    //前置节点
    struct listNode *prev;
    //后置节点
    struct listNode *next;
    //节点的值
    void *value;
}
  • 双端链表,获取节点的前置节点和后置节点的复杂度都是O(1)。
  • 无环链表,表头指针的prev和表尾指针的next都是指向NULL。
  • list结构的head指针和tail指针能快速获取表头结点和表尾节点,复杂度是O(1)。
  • 可以通过list结构的len属性来获取链表中节点的数量,复杂度是O(1)。

命令 #

  • lpush/rpush k1 v1 v2 v3 从左/右边插入
  • lpop/rpop k1 从左/又边吐出一个值
  • lindex key index按照索引下标获取元素
  • len key获得列表的长度
  • lset key index value 将key的下标为index设置为value
  • lrange key start stop 按照下标索引获得元素,0表示左边第一个,-1表示右边第一个。
  • lrem key n value 删除n个value

hash #

命令 #

  • hset key field value设置值
  • hget key field获取值
  • hdel key field[field...]删除一个或多个键值对
  • hlen key计算field的个数
  • hmget key field [field...] 批量获取
  • hmset key field value [field value ...]批量设置
  • hexists key field判断field是否存在
  • hkeys key获取所有field
  • hvals key获取所有value
  • hstrlen key field获取value字符串长度