Akka(42): Http:身份验证 - authentication, autorization and use of raw headers
当我们把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的更多相关文章
- Akka(42): Http:身份验证 - authentication, authorization and use of raw headers
当我们把Akka-http作为数据库数据交换工具时,数据是以Source[ROW,_]形式存放在Entity里的.很多时候除数据之外我们可能需要进行一些附加的信息传递如对数据的具体处理方式等.我们可以 ...
- 也谈Asp.net 中的身份验证
钱李峰 的这篇博文<Asp.net中的认证与授权>已对Asp.net 中的身份验证进行了不错实践.而我这篇博文,是从初学者的角度补充了一些基础的概念,以便能有个清晰的认识. 一.配置安全身 ...
- .net core使用ocelot---第二篇 身份验证
简介原文链接 .net core使用ocelot---第一篇 简单使用 接上文,我将继续介绍使用asp.net core 创建API网关,主要介绍身份验证(authentication )相 ...
- 学学dotnet core中的身份验证和授权-1-概念
前言 身份验证: Authentication 授权: Authorization net core 中的身份验证和授权这两个部分,是相辅相成的.当初我在学在部分的时候,是看的 net core 官网 ...
- Angular 应用中的登陆与身份验证
Angular 经常会被用到后台和管理工具的开发,这两类都会需要对用户进行鉴权.而鉴权的第一步,就是进行身份验证.由于 Angular 是单页应用,会在一开始,就把大部分的资源加载到浏览器中,所以就更 ...
- 【记录】ASP.NET MVC 4/5 Authentication 身份验证无效
在 ASP.NET MVC 4/5 应用程序发布的时候,遇到一个问题,在本应用程序中进行身份验证是可以,但不能和其他"二级域名"共享,在其他应用程序身份验证,不能和本应用程序共享, ...
- SQL Server安全(2/11):身份验证(Authentication)
在保密你的服务器和数据,防备当前复杂的攻击,SQL Server有你需要的一切.但在你能有效使用这些安全功能前,你需要理解你面对的威胁和一些基本的安全概念.这篇文章提供了基础,因此你可以对SQL Se ...
- 发布Restful服务时出现IIS 指定了身份验证方案错误时的解决方案(IIS specified authentication schemes)
发布RESTful服务,当访问.svc文件时出现如下错误时: IIS 指定了身份验证方案“IntegratedWindowsAuthentication, Anonymous”,但绑定仅支持一种身份验 ...
- Zend Framework 2参考Zend\Authentication(摘要式身份验证)
Zend Framework 2参考Zend\Authentication(摘要式身份验证) 介绍 摘要式身份验证是HTTP身份验证的方法,提高了基本身份验证时提供的方式进行身份验证,而无需在网络上以 ...
随机推荐
- Java基础笔记2
1. 变量的定义 int money; int 变量类型 money 变量名 money=1000;变量的值 2. 自动类型转换 ①类型要兼容 容器 (水杯---竹篮---碗) ②目标类型 ...
- 读书笔记-你不知道的JS中-promise
之前的笔记没保存没掉了,好气,重新写! 填坑-- 现在与将来 在单个JS文件中,程序由许多块组成,这些块有的现在执行,有的将来执行,最常见的块单位是函数. 程序中'将来'执行的部分并不一定在'现在'运 ...
- 学习笔记 intent属性
Android开发学习笔记:Intent的简介以及属性的详解 2011-08-08 17:20:48 标签:Intent 移动开发 Android 休闲 详解 原创作品,允许转载,转载时请务必以超链接 ...
- _.contains is not a function
在使用lodash的时候报_.contains is not a function,这是因为从lodash V3.10.1开始,将去掉contains函数,改用includes. 可以换为:_.con ...
- JavaScript基础一(js基础函数与运算符)
[使用js的三种方式] 1.在HTML标签中,直接内嵌js(并不提倡使用) <button onclick=" alert('点就点')"> 点我啊</butto ...
- css基础语法一(选择器与css导入方式)
页面中,所有的CSS代码,需要写入到<style></style>标签中.style标签的type属性应该选择text/css,但是type属性可以省略. CSS修改页面中的所 ...
- JavaScript系列----作用域链和闭包
1.作用域链 1.1.什么是作用域 谈起作用域链,我们就不得不从作用域开始谈起.因为所谓的作用域链就是由多个作用域组成的.那么, 什么是作用域呢? 1.1.1作用域是一个函数在执行时期的执行环境. 每 ...
- Linux 基本命令-----常用操作分类
Linux/Unix 命令格式: 命令名 [选项] [参数] 注:[]中的内容代表内容可以省略 例:$ ls $ ls -l #-l 是选项 开始符号: 文件名 或 文件夹名 .当前文件夹 ..上一级 ...
- HTTP请求过程(http是一种无状态协议,即不建立持久的连接)
一.一个完整的HTTP请求,通常有7个步骤: 1.建立TCP连接: 2.web浏览器向web服务器发送请求命令: 3.浏览器发送请求头信息: 4.服务器应答: 5.服务器发送应答头信息: 6.服务器向 ...
- 万年历java
public void showTime(){/*万年历 : 1900年1月20号是星期几?1月1号是星期一1月8号是星期一1月15号是星期一1%7 = 18%7 = 115%7 = 1★: 1. ...