Akka(42): Http:身份验证 - authentication, authorization 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, authorization and use of raw headers的更多相关文章
- Akka(42): Http:身份验证 - authentication, autorization 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 是单页应用,会在一开始,就把大部分的资源加载到浏览器中,所以就更 ...
- Chapter 2 User Authentication, Authorization, and Security(1):选择Windows和SQL 身份验证
原文出处:http://blog.csdn.net/dba_huangzj/article/details/38657111,专题目录:http://blog.csdn.net/dba_huangzj ...
- ASP.NET 中的 authentication(验证)与authorization(授权)
这两个东西很绕口,也绕脑袋. 一般来说,了解authentication(验证)的用法即可,用于自定义的用户验证. authorization(授权)主要通过计算机信息来控制. “*”:所有用户: “ ...
- asp.net 如何配置authentication,完成基于表单的身份验证
步骤一: 在根目录下的web.config中加入: <system.web> <authentication mode="Forms"> ...
- [翻译] API测试最佳实践 - 身份验证(Authentication)
API测试最佳实践 - 身份验证 适用等级:高级 1. 概况 身份验证通常被定义为是对某个资源的身份的确认的活动,这里面资源的身份指代的是API的消费者(或者说是调用者).一旦一个用户的身份验证通过了 ...
随机推荐
- mybatis-mysql类型映射
JDBC Type Java Type CHAR String VARCHAR String LONGVARCHAR String NUMERIC java.math.BigDecimal DECIM ...
- 组合数问题(NOIP2016)
题目链接:组合数问题 这道题可以算当年第二简单的. 这里要用到两个技巧: 用杨辉三角递推计算组合数 运用前缀和 有了这两点,这道题就出来了. 我们先运用杨辉三角推出题目范围内所能用到的所有组合数,然后 ...
- gcc -ldl 选项作用
如果你的程序中使用dlopen.dlsym.dlclose.dlerror 显示加载动态库,需要设置链接选项 -ldl 加载动态链接库,首先为共享库分配物理内存,然后在进程对应的页表项中建立虚拟页和物 ...
- GUI的最终选择Tkinter模块初级篇
一.Tkinter模块的基本使用 1)实例化窗口程序 import tkinter as tk app = tk.Tk() app.title("FishC Demo") app. ...
- Mathematics | Mean, Variance and Standard Deviation
Mean is average of a given set of data. Let us consider below example These eight data points have t ...
- 2019.01.19 洛谷P2787 语文1(chin1)- 理理思维(ODT)
传送门 ODTODTODT水题. 题意:有一个字母序列,支持区间赋值,查询区间某个字母的数量,区间按字母序排序. 思路: 可以开262626棵线段树搞过去,然而也可以用ODTODTODT秒掉. 如果用 ...
- yyparse() and yylex()
Yacc 与 Lex 快速入门 yyparse() returns a value of 0 if the input it parses is valid according to the give ...
- best-case analysis in real-time system
ECRTS: Exact Best-Case Response Time Analysis of Fixed Priority Scheduled Tasks motivation Real-time ...
- maven学习之一:maven安装
1.下载maven: 地址:https://maven.apache.org/ 点击download后; 解压: 解压后放在d:\develop目录下 下面我们去配置环境变量,找到计算机,右键,找到属 ...
- hadoop flume 架构及监控的部署
1 Flume架构解释 Flume概念 Flume是一个分布式 ,可靠的,和高可用的,海量的日志聚合系统 支持在系统中定制各类的数据发送方 用于收集数据 提供简单的数据提取能力 并写入到各种接受方 ...