当我们把Akka-http作为数据库数据交换工具时,数据是以Source[ROW,_]形式存放在Entity里的。很多时候除数据之外我们可能需要进行一些附加的信息传递如对数据的具体处理方式等。我们可以通过Akka-http的raw-header来实现附加自定义消息的传递,这项功能可以通过Akka-http提供的raw-header筛选功能来实现。在客户端我们把附加消息放在HttpRequest的raw header里,如下:

  import akka.http.scaladsl.model.headers._
val request = HttpRequest(HttpMethods.POST,uri = s"http://localhost:8011/rows")
.addHeader(RawHeader("action","insert:county"))

在这里客户端注明上传数据应插入county表。服务端可以像下面这样获取这项信息:

             optionalHeaderValueByName("action") {
case Some(action) =>
entity(asSourceOf[County]) { source =>
val futofNames: Future[List[String]] =
source.runFold(List[String](""))((acc, b) => acc ++ List(b.name))
complete(s"Received rows for $action")
}
case None => complete ("No action specified!")
}

Akka-http通过Credential类的Directive提供了authentication和authorization。在客户端可以用下面的方法提供自己的用户身份信息:

  import akka.http.scaladsl.model.headers._
val request = HttpRequest(HttpMethods.POST,uri = s"http://localhost:8011/rows")
.addHeader(RawHeader("action","insert:county"))
.addCredentials(BasicHttpCredentials("john", "p4ssw0rd"))

服务端对客户端的身份验证处理方法如下:

  import akka.http.scaladsl.server.directives.Credentials
def myUserPassAuthenticator(credentials: Credentials): Future[Option[User]] = {
implicit val blockingDispatcher = httpSys.dispatchers.lookup("akka-httpblocking-ops-dispatcher")
credentials match {
case p @ Credentials.Provided(id) =>
Future {
// potentially
if (p.verify("p4ssw0rd")) Some(User(id))
else None
}
case _ => Future.successful(None)
}
} case class User(name: String)
val validUsers = Set("john","peter","tiger","susan")
def hasAdminPermissions(user: User): Future[Boolean] = {
implicit val blockingDispatcher = httpSys.dispatchers.lookup("akka-httpblocking-ops-dispatcher")
Future.successful(validUsers.contains(user.name))
}

下面是Credential-Directive的使用方法:

         authenticateBasicAsync(realm = "secure site", userPassAuthenticator) { user =>
authorizeAsync(_ => hasPermissions(user)) {
withoutSizeLimit {
handleExceptions(postExceptionHandler) {
optionalHeaderValueByName("action") {
case Some(action) =>
entity(asSourceOf[County]) { source =>
val futofNames: Future[List[String]] =
source.runFold(List[String](""))((acc, b) => acc ++ List(b.name))
complete(s"Received rows for $action sent from $user")
}
case None => complete(s"$user did not specify action for uploaded rows!")
}
}
}
}
}

下面是本次讨论的示范代码:

客户端:

import akka.actor._
import akka.stream._
import akka.stream.scaladsl._
import akka.http.scaladsl.Http
import scala.util._
import akka._
import akka.http.scaladsl.common._
import spray.json.DefaultJsonProtocol
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport
import akka.http.scaladsl.common.EntityStreamingSupport
import akka.http.scaladsl.model._
import spray.json._ trait MyFormats extends SprayJsonSupport with DefaultJsonProtocol
object Converters extends MyFormats {
case class County(id: Int, name: String)
implicit val countyFormat = jsonFormat2(County)
} object HttpClientDemo extends App {
import Converters._ implicit val sys = ActorSystem("ClientSys")
implicit val mat = ActorMaterializer()
implicit val ec = sys.dispatcher implicit val jsonStreamingSupport: JsonEntityStreamingSupport = EntityStreamingSupport.json() import akka.util.ByteString
import akka.http.scaladsl.model.HttpEntity.limitableByteSource val source: Source[County,NotUsed] = Source( to ).map {i => County(i, s"广西壮族自治区地市县编号 #$i")}
def countyToByteString(c: County) = {
ByteString(c.toJson.toString)
}
val flowCountyToByteString : Flow[County,ByteString,NotUsed] = Flow.fromFunction(countyToByteString) val rowBytes = limitableByteSource(source via flowCountyToByteString) import akka.http.scaladsl.model.headers._
val request = HttpRequest(HttpMethods.POST,uri = s"http://localhost:8011/rows")
.addHeader(RawHeader("action","insert:county"))
.addCredentials(BasicHttpCredentials("john", "p4ssw0rd")) val data = HttpEntity(
ContentTypes.`application/json`,
rowBytes
) def uploadRows(request: HttpRequest, dataEntity: RequestEntity) = {
val futResp = Http(sys).singleRequest(
request.copy(entity = dataEntity)
)
futResp
.andThen {
case Success(r@HttpResponse(StatusCodes.OK, _, entity, _)) =>
entity.dataBytes.map(_.utf8String).runForeach(println)
case Success(r@HttpResponse(code, _, _, _)) =>
println(s"Upload request failed, response code: $code")
r.discardEntityBytes()
case Success(_) => println("Unable to Upload file!")
case Failure(err) => println(s"Upload failed: ${err.getMessage}") }
} uploadRows(request,data) scala.io.StdIn.readLine() sys.terminate() }

服务端:

import akka.actor._
import akka.stream._
import akka.stream.scaladsl._
import akka.http.scaladsl.Http
import akka._
import akka.http.scaladsl.common._
import spray.json.DefaultJsonProtocol
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport
import scala.concurrent._
import akka.http.scaladsl.server._
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.model._ trait MyFormats extends SprayJsonSupport with DefaultJsonProtocol
object Converters extends MyFormats {
case class County(id: Int, name: String)
val source: Source[County, NotUsed] = Source( to ).map { i => County(i, s"中国广东省地区编号 #$i") }
implicit val countyFormat = jsonFormat2(County)
} object HttpServerDemo extends App { import Converters._ implicit val httpSys = ActorSystem("httpSystem")
implicit val httpMat = ActorMaterializer()
implicit val httpEC = httpSys.dispatcher implicit val jsonStreamingSupport = EntityStreamingSupport.json()
.withParallelMarshalling(parallelism = , unordered = false) def postExceptionHandler: ExceptionHandler =
ExceptionHandler {
case _: RuntimeException =>
extractRequest { req =>
req.discardEntityBytes()
complete((StatusCodes.InternalServerError.intValue, "Upload Failed!"))
}
} import akka.http.scaladsl.server.directives.Credentials
def userPassAuthenticator(credentials: Credentials): Future[Option[User]] = {
implicit val blockingDispatcher = httpSys.dispatchers.lookup("akka-httpblocking-ops-dispatcher")
credentials match {
case p @ Credentials.Provided(id) =>
Future {
// potentially
if (p.verify("p4ssw0rd")) Some(User(id))
else None
}
case _ => Future.successful(None)
}
} case class User(name: String)
val validUsers = Set("john","peter","tiger","susan")
def hasPermissions(user: User): Future[Boolean] = {
implicit val blockingDispatcher = httpSys.dispatchers.lookup("akka-httpblocking-ops-dispatcher")
Future.successful(validUsers.contains(user.name))
} val route =
path("rows") {
get {
complete {
source
}
} ~
post {
authenticateBasicAsync(realm = "secure site", userPassAuthenticator) { user =>
authorizeAsync(_ => hasPermissions(user)) {
withoutSizeLimit {
handleExceptions(postExceptionHandler) {
optionalHeaderValueByName("action") {
case Some(action) =>
entity(asSourceOf[County]) { source =>
val futofNames: Future[List[String]] =
source.runFold(List[String](""))((acc, b) => acc ++ List(b.name))
complete(s"Received rows for $action sent from $user")
}
case None => complete(s"$user did not specify action for uploaded rows!")
}
}
}
}
}
}
} val (port, host) = (,"localhost") val bindingFuture = Http().bindAndHandle(route,host,port) println(s"Server running at $host $port. Press any key to exit ...") scala.io.StdIn.readLine() bindingFuture.flatMap(_.unbind())
.onComplete(_ => httpSys.terminate()) }

Akka(42): Http:身份验证 - authentication, autorization and use of raw headers的更多相关文章

  1. Akka(42): Http:身份验证 - authentication, authorization and use of raw headers

    当我们把Akka-http作为数据库数据交换工具时,数据是以Source[ROW,_]形式存放在Entity里的.很多时候除数据之外我们可能需要进行一些附加的信息传递如对数据的具体处理方式等.我们可以 ...

  2. 也谈Asp.net 中的身份验证

    钱李峰 的这篇博文<Asp.net中的认证与授权>已对Asp.net 中的身份验证进行了不错实践.而我这篇博文,是从初学者的角度补充了一些基础的概念,以便能有个清晰的认识. 一.配置安全身 ...

  3. .net core使用ocelot---第二篇 身份验证

    简介原文链接      .net core使用ocelot---第一篇 简单使用 接上文,我将继续介绍使用asp.net core 创建API网关,主要介绍身份验证(authentication )相 ...

  4. 学学dotnet core中的身份验证和授权-1-概念

    前言 身份验证: Authentication 授权: Authorization net core 中的身份验证和授权这两个部分,是相辅相成的.当初我在学在部分的时候,是看的 net core 官网 ...

  5. Angular 应用中的登陆与身份验证

    Angular 经常会被用到后台和管理工具的开发,这两类都会需要对用户进行鉴权.而鉴权的第一步,就是进行身份验证.由于 Angular 是单页应用,会在一开始,就把大部分的资源加载到浏览器中,所以就更 ...

  6. 【记录】ASP.NET MVC 4/5 Authentication 身份验证无效

    在 ASP.NET MVC 4/5 应用程序发布的时候,遇到一个问题,在本应用程序中进行身份验证是可以,但不能和其他"二级域名"共享,在其他应用程序身份验证,不能和本应用程序共享, ...

  7. SQL Server安全(2/11):身份验证(Authentication)

    在保密你的服务器和数据,防备当前复杂的攻击,SQL Server有你需要的一切.但在你能有效使用这些安全功能前,你需要理解你面对的威胁和一些基本的安全概念.这篇文章提供了基础,因此你可以对SQL Se ...

  8. 发布Restful服务时出现IIS 指定了身份验证方案错误时的解决方案(IIS specified authentication schemes)

    发布RESTful服务,当访问.svc文件时出现如下错误时: IIS 指定了身份验证方案“IntegratedWindowsAuthentication, Anonymous”,但绑定仅支持一种身份验 ...

  9. Zend Framework 2参考Zend\Authentication(摘要式身份验证)

    Zend Framework 2参考Zend\Authentication(摘要式身份验证) 介绍 摘要式身份验证是HTTP身份验证的方法,提高了基本身份验证时提供的方式进行身份验证,而无需在网络上以 ...

随机推荐

  1. 读书笔记-你不知道的JS上-闭包与模块

    闭包定义 当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域之外执行. 看一段最简单的闭包代码: function foo() { var a = 2; //闭包 fun ...

  2. 值得学习的C/C++开源框架(转)

    值得学习的C语言开源项目 - 1. Webbench Webbench是一个在linux下使用的非常简单的网站压测工具.它使用fork()模拟多个客户端同时访问我们设定的URL,测试网站在压力下工作的 ...

  3. HTML学习笔记 div布局及table布局案例 第三节 (原创)参考使用表

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. 新增加的HTTP状态码 -- 103

    IETF公布了新的HTTP状态码-103, 总结一下就是提前预加载(css.js)文档,提升用户的访问速度. Summary: a new status code that lets the serv ...

  5. spa(单页应用)中,使用history模式时,微信长按识别二维码在ios下失效的问题

    spa(单页应用,vue)中,使用history模式时,微信长按识别二维码在ios下失效的问题. 触发条件: spa单页应用: 路由模式 history 从其他页面跳转到带有微信二维码识别的页面(不是 ...

  6. js规范

    js规范 Array 和 Object 直接量 为了避免这些歧义, 我们应该使用更易读的直接量来声明. var a = [x1, x2, x3]; var a2 = [x1, x2]; var a3 ...

  7. centos7.2构建Python3.5开发环境

    1.本次使用的是一台全新的腾讯云主机,首先获取linux系统版本信息. [root@VM_46_121_centos ~]# cat /etc/redhat-release <本系统默认自带py ...

  8. C# 链接MySql数据库

    C# 链接MySql数据库只得注意的几点: 1.C#链接MySql数据库要在网上下载一个mysql-connector-net-6.0.4-noinstall.rar  这里面放的都是一堆dll .将 ...

  9. linux C/C++开发环境搭建指南

    一.安装基本开发环境 1.配置GCC 刚装好的系统中已经有GCC了,但是这个GCC什么文件都不能编译,因为没有一些必须的头文件,所以要安装build-essential这个软件包,安装了这个包会自动安 ...

  10. ZooKeeper全面介绍

    ZooKeeper简介 ZooKeeper是分布式服务框架,主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务.状态同步服务.集群管理.分布式应用配置项的管理等等.   ZooKe ...