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

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

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

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

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

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

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

  1. import akka.http.scaladsl.server.directives.Credentials
  2. def myUserPassAuthenticator(credentials: Credentials): Future[Option[User]] = {
  3. implicit val blockingDispatcher = httpSys.dispatchers.lookup("akka-httpblocking-ops-dispatcher")
  4. credentials match {
  5. case p @ Credentials.Provided(id) =>
  6. Future {
  7. // potentially
  8. if (p.verify("p4ssw0rd")) Some(User(id))
  9. else None
  10. }
  11. case _ => Future.successful(None)
  12. }
  13. }
  14.  
  15. case class User(name: String)
  16. val validUsers = Set("john","peter","tiger","susan")
  17. def hasAdminPermissions(user: User): Future[Boolean] = {
  18. implicit val blockingDispatcher = httpSys.dispatchers.lookup("akka-httpblocking-ops-dispatcher")
  19. Future.successful(validUsers.contains(user.name))
  20. }

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

  1. authenticateBasicAsync(realm = "secure site", userPassAuthenticator) { user =>
  2. authorizeAsync(_ => hasPermissions(user)) {
  3. withoutSizeLimit {
  4. handleExceptions(postExceptionHandler) {
  5. optionalHeaderValueByName("action") {
  6. case Some(action) =>
  7. entity(asSourceOf[County]) { source =>
  8. val futofNames: Future[List[String]] =
  9. source.runFold(List[String](""))((acc, b) => acc ++ List(b.name))
  10. complete(s"Received rows for $action sent from $user")
  11. }
  12. case None => complete(s"$user did not specify action for uploaded rows!")
  13. }
  14. }
  15. }
  16. }
  17. }

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

客户端:

  1. import akka.actor._
  2. import akka.stream._
  3. import akka.stream.scaladsl._
  4. import akka.http.scaladsl.Http
  5. import scala.util._
  6. import akka._
  7. import akka.http.scaladsl.common._
  8. import spray.json.DefaultJsonProtocol
  9. import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport
  10. import akka.http.scaladsl.common.EntityStreamingSupport
  11. import akka.http.scaladsl.model._
  12. import spray.json._
  13.  
  14. trait MyFormats extends SprayJsonSupport with DefaultJsonProtocol
  15. object Converters extends MyFormats {
  16. case class County(id: Int, name: String)
  17. implicit val countyFormat = jsonFormat2(County)
  18. }
  19.  
  20. object HttpClientDemo extends App {
  21. import Converters._
  22.  
  23. implicit val sys = ActorSystem("ClientSys")
  24. implicit val mat = ActorMaterializer()
  25. implicit val ec = sys.dispatcher
  26.  
  27. implicit val jsonStreamingSupport: JsonEntityStreamingSupport = EntityStreamingSupport.json()
  28.  
  29. import akka.util.ByteString
  30. import akka.http.scaladsl.model.HttpEntity.limitableByteSource
  31.  
  32. val source: Source[County,NotUsed] = Source( to ).map {i => County(i, s"广西壮族自治区地市县编号 #$i")}
  33. def countyToByteString(c: County) = {
  34. ByteString(c.toJson.toString)
  35. }
  36. val flowCountyToByteString : Flow[County,ByteString,NotUsed] = Flow.fromFunction(countyToByteString)
  37.  
  38. val rowBytes = limitableByteSource(source via flowCountyToByteString)
  39.  
  40. import akka.http.scaladsl.model.headers._
  41. val request = HttpRequest(HttpMethods.POST,uri = s"http://localhost:8011/rows")
  42. .addHeader(RawHeader("action","insert:county"))
  43. .addCredentials(BasicHttpCredentials("john", "p4ssw0rd"))
  44.  
  45. val data = HttpEntity(
  46. ContentTypes.`application/json`,
  47. rowBytes
  48. )
  49.  
  50. def uploadRows(request: HttpRequest, dataEntity: RequestEntity) = {
  51. val futResp = Http(sys).singleRequest(
  52. request.copy(entity = dataEntity)
  53. )
  54. futResp
  55. .andThen {
  56. case Success(r@HttpResponse(StatusCodes.OK, _, entity, _)) =>
  57. entity.dataBytes.map(_.utf8String).runForeach(println)
  58. case Success(r@HttpResponse(code, _, _, _)) =>
  59. println(s"Upload request failed, response code: $code")
  60. r.discardEntityBytes()
  61. case Success(_) => println("Unable to Upload file!")
  62. case Failure(err) => println(s"Upload failed: ${err.getMessage}")
  63.  
  64. }
  65. }
  66.  
  67. uploadRows(request,data)
  68.  
  69. scala.io.StdIn.readLine()
  70.  
  71. sys.terminate()
  72.  
  73. }

服务端:

  1. import akka.actor._
  2. import akka.stream._
  3. import akka.stream.scaladsl._
  4. import akka.http.scaladsl.Http
  5. import akka._
  6. import akka.http.scaladsl.common._
  7. import spray.json.DefaultJsonProtocol
  8. import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport
  9. import scala.concurrent._
  10. import akka.http.scaladsl.server._
  11. import akka.http.scaladsl.server.Directives._
  12. import akka.http.scaladsl.model._
  13.  
  14. trait MyFormats extends SprayJsonSupport with DefaultJsonProtocol
  15. object Converters extends MyFormats {
  16. case class County(id: Int, name: String)
  17. val source: Source[County, NotUsed] = Source( to ).map { i => County(i, s"中国广东省地区编号 #$i") }
  18. implicit val countyFormat = jsonFormat2(County)
  19. }
  20.  
  21. object HttpServerDemo extends App {
  22.  
  23. import Converters._
  24.  
  25. implicit val httpSys = ActorSystem("httpSystem")
  26. implicit val httpMat = ActorMaterializer()
  27. implicit val httpEC = httpSys.dispatcher
  28.  
  29. implicit val jsonStreamingSupport = EntityStreamingSupport.json()
  30. .withParallelMarshalling(parallelism = , unordered = false)
  31.  
  32. def postExceptionHandler: ExceptionHandler =
  33. ExceptionHandler {
  34. case _: RuntimeException =>
  35. extractRequest { req =>
  36. req.discardEntityBytes()
  37. complete((StatusCodes.InternalServerError.intValue, "Upload Failed!"))
  38. }
  39. }
  40.  
  41. import akka.http.scaladsl.server.directives.Credentials
  42. def userPassAuthenticator(credentials: Credentials): Future[Option[User]] = {
  43. implicit val blockingDispatcher = httpSys.dispatchers.lookup("akka-httpblocking-ops-dispatcher")
  44. credentials match {
  45. case p @ Credentials.Provided(id) =>
  46. Future {
  47. // potentially
  48. if (p.verify("p4ssw0rd")) Some(User(id))
  49. else None
  50. }
  51. case _ => Future.successful(None)
  52. }
  53. }
  54.  
  55. case class User(name: String)
  56. val validUsers = Set("john","peter","tiger","susan")
  57. def hasPermissions(user: User): Future[Boolean] = {
  58. implicit val blockingDispatcher = httpSys.dispatchers.lookup("akka-httpblocking-ops-dispatcher")
  59. Future.successful(validUsers.contains(user.name))
  60. }
  61.  
  62. val route =
  63. path("rows") {
  64. get {
  65. complete {
  66. source
  67. }
  68. } ~
  69. post {
  70. authenticateBasicAsync(realm = "secure site", userPassAuthenticator) { user =>
  71. authorizeAsync(_ => hasPermissions(user)) {
  72. withoutSizeLimit {
  73. handleExceptions(postExceptionHandler) {
  74. optionalHeaderValueByName("action") {
  75. case Some(action) =>
  76. entity(asSourceOf[County]) { source =>
  77. val futofNames: Future[List[String]] =
  78. source.runFold(List[String](""))((acc, b) => acc ++ List(b.name))
  79. complete(s"Received rows for $action sent from $user")
  80. }
  81. case None => complete(s"$user did not specify action for uploaded rows!")
  82. }
  83. }
  84. }
  85. }
  86. }
  87. }
  88. }
  89.  
  90. val (port, host) = (,"localhost")
  91.  
  92. val bindingFuture = Http().bindAndHandle(route,host,port)
  93.  
  94. println(s"Server running at $host $port. Press any key to exit ...")
  95.  
  96. scala.io.StdIn.readLine()
  97.  
  98. bindingFuture.flatMap(_.unbind())
  99. .onComplete(_ => httpSys.terminate())
  100.  
  101. }

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. centos 源码安装python

    一.准备环境 首先在官网下载想要的python对应版本http//www.python.org/downloads/source 下载tgz就可以了.文件有两种 1,Python-版本号.tgz(解压 ...

  2. Javaweb项目开发的前后端解耦的必要性

    JavaWeb项目为何我们要放弃jsp?为何要前后端解耦?为何要动静分离? 使用jsp的痛点: 1.jsp上动态资源和静态资源全部耦合在一起,服务器压力大,因为服务器会收到各种静态资源的http请求, ...

  3. 用git上传本地文件到github

    1.在自己的github账号下新建仓库--------得到github仓库地址 2.本地安装git---在将要克隆的文件夹下 右击点击Git Bash Here 3.输入命令 $ git clone ...

  4. CQRS微服务架构模式

    ​什么是微服务? 这是维基百科里面的定义:“微服务是面向服务架构(SOA)架构风格的一种变体,它将应用程序构建为一系列松散耦合的服务.在微服务体系结构中,服务应该是细粒度的,协议应该是轻量级的.将应用 ...

  5. JS5模拟类

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  6. C#中结构体定义并转换字节数组

    最近的项目在做socket通信报文解析的时候,用到了结构体与字节数组的转换:由于客户端采用C++开发,服务端采用C#开发,所以双方必须保证各自定义结构体成员类型和长度一致才能保证报文解析的正确性,这一 ...

  7. Cordova cannot add Android failed with exit code ENOENT

    这可能是系统环境变量损坏了 解决方案:在系统变量path如果没用下面的变量就加上%SystemRoot%\system32; %SystemRoot%; %SystemRoot%\System32\W ...

  8. 将非常规Json字符串转换为常用的json对象

    如下所示,这是一个已经转换为Json对象的非常规Json字符串,原来是一个Json类型的字符串,在转换为Json对象时,查询资料发现有两种转换法,.parse()和.eval()方法,但是前辈们都极其 ...

  9. Node.js初探之POST方式传输

    小知识:POST比GET传输的数据量大很多 POST发数据--"分段" 实例: 准备一个form.html文件: <!DOCTYPE html> <html> ...

  10. python基础-------模块与包(一)

    模块与包 Python中的py文件我们拿来调用的为之模块:主要有内置模块(Python解释器自带),第三方模块(别的开发者开发的),自定义模块. 目前我们学习的是内置模块与第三方模块. 通过impor ...