设为首页 加入收藏

TOP

Akka-CQRS(14)- Http标准安全解决方案:OAuth2-资源使用授权(一)
2019-08-15 00:10:43 】 浏览:103
Tags:Akka-CQRS Http 标准 安全 解决方案 OAuth2- 资源 使用 授权

   上一篇讨论了SSL/TLS安全连接,主要是一套在通信层面的数据加密解决方案。但我们更需要一套方案来验证客户端。要把不能通过验证的网络请求过滤掉。

OAuth2是一套行业标准的网络资源使用授权协议,也就是为用户提供一种授权凭证,用户凭授权凭证来使用网络资源。申请凭证、然后使用凭证进行网络操作流程如下:

 

??

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

实际上OAuth2是一套3方授权模式,但我们只需要资源管理方授权,所以划去了1、2两个步骤。剩下的两个步骤,包括:申请令牌,使用令牌,这些在官方文件中有详细描述。用户身份和令牌的传递是通过Http Header实现的,具体情况可参考RFC2617,RFC6750

简单来说:用户向服务器提交身份信息申请令牌,下面是一个HttpRequest样例:

POST /token HTTP/1.1 Host: server.example.com Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW Content-Type: application/x-www-form-urlencoded

上面Basic后面一串代码就是 user+password的加密文,它的产生方法示范如下:

final case class BasicHttpCredentials(username: String, password: String) extends jm.headers.BasicHttpCredentials { val cookie = { val userPass = username + ':' + password val bytes = userPass.getBytes(`UTF-8`.nioCharset) Base64.rfc2045.encodeToChar(bytes, false) } def render[R <: Rendering](r: R): r.type = r ~~ "Basic " ~~ cookie override def scheme: String = "Basic"
  override def token: String = String.valueOf(cookie) override def params: Map[String, String] = Map.empty }

注:在OAuth2版本中如果使用https://,则容许明文用户和密码。

服务端在返回的HttpResponse中返回令牌access_token:

{"access_token":"2e510027-0eb9-4367-b310-68e1bab9dc3d", "token_type":"bearer", "expires_in":3600}

注意:这个expires_in是应用系统自定义内部使用的参数,也就是说应用系统必须自备令牌过期失效处理机制。

得到令牌后每个使用网络资源的Request都必须在Authorization类Header里附带这个令牌,如:

   GET /resource HTTP/1.1 Host: server.example.com Authorization: Bearer 2e510027-0eb9-4367-b310-68e1bab9dc3d

Bearer后就是服务端返回的令牌值。我们还是设计一个例子来示范整个授权使用过程。先看看下面一些基本操作代码:

object JsonMarshaller extends SprayJsonSupport with DefaultJsonProtocol { case class UserInfo(username: String, password: String) case class AuthToken(access_token: String = java.util.UUID.randomUUID().toString, token_type: String = "bearer", expires_in: Int = 3600) case class AuthUser(credentials: UserInfo, token: AuthToken = new AuthToken(expires_in = 60 * 60 * 8), loggedInAt: String = LocalDateTime.now().toString) val validUsers = Seq(UserInfo("johnny", "p4ssw0rd"),UserInfo("tiger", "secret")) val loggedInUsers = mutable.ArrayBuffer.empty[AuthUser] def getValidUser(credentials: Credentials): Option[UserInfo] = credentials match { case p @ Credentials.Provided(_) => validUsers.find(user => user.username == p.identifier && p.verify(user.password)) case _ => None } def authenticateUser(credentials: Credentials): Option[AuthUser] = credentials match { case p @ Credentials.Provided(_) => loggedInUsers.find(user => p.verify(user.token.access_token)) case _ => None } implicit val fmtCredentials = jsonFormat2(UserInfo.apply) implicit val fmtToken = jsonFormat3(AuthToken.apply) implicit val fmtUser = jsonFormat3(AuthUser.apply) }

validUers: Seq[UserInfo] 模拟是个在服务端数据库里的用户登记表,loggedInUsers是一个已经通过验证的用户请单。函数 getValidUser(credentials: Credentials) 用传人参数Credentials来获取用户信息Option[UserInfo]。Credentials是这样定义的:

object Credentials { case object Missing extends Credentials abstract case class Provided(identifier: String) extends Credentials { /** * First appli
首页 上一页 1 2 3 4 下一页 尾页 1/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Akka-CQRS(15)- Http标准安全解.. 下一篇restapi(0)- 平台数据维护,写..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目