Spray中的Authentication和JMeter测试
Spray Authentication
在Spray中,如果需要对REST API添加认证,可以使用Spray提供的Authenticate功能。本质上,Authenticate属于安全指令(Security Directive)提供的功能。它的接口定义本质上为:
def authenticate[T](auth: => Future[Authentication[T]])(implicit executor: ExecutionContext): Directive1[T]
def authenticate[T](auth: ContextAuthenticator[T])(implicit executor: ExecutionContext): Directive1[T]
Spray使用了Magnet Pattern,使其可以编写出更符合DSL风格的API。所以我们看到的authenticate()方法的实现实际为:
trait SecurityDirectives extends scala.AnyRef {
def authenticate[T](magnet : spray.routing.directives.AuthMagnet[T]) : spray.routing.Directive1[T] = ???
}
正是因为运用了Magnet Pattern,我们可以直接在Path中通过authenticate添加认证功能,例如:
def myUserPassAuthenticator(userPass: Option[UserPass]): Future[Option[String]] =
Future {
if (userPass.exists(up => up.user == "John" && up.pass == "p4ssw0rd")) Some("John")
else None
}
val customerRoute =
path("customers") {
authenticate(BasicAuth(myUserPassAuthenticator _, realm = "admin area")) { user =>
get {
handleRequest {
AllCustomers
}
} ~ post {
entity(as[Customer]) {
customer =>
handleRequest {
CreateCustomer(customer.email, customer.name)
}
}
}
}
}
Spray Authentication通过BasicHttpAuthenticator类来支持Basic Access Authentication。上面代码片段中的BasicAuth是一个对象,提供了多个构造函数重载。这段代码中传递了两个参数:第一个参数为UserPassAuthenticator类型;第二个参数用于指定认证的realm。
UserPassAuthenticator是一个type,实质为一个函数:
type UserPassAuthenticator[T] = Option[UserPass] => Future[Option[T]]
上面代码中的myUserPassAuthenticator就是自定义的一个UserPassAuthenticator。显然,BasicAuth接收一个函数作为参数,使得我们可以更容易自定义。若要通过认证,我们可以创建BasicHttpCredentials对象,将其加入到authorization header中。Spray也支持配置的形式管理用户信息,具体内容可参见Spray的官方文档Authentication。
JMeter测试
我用JMeter来测试这个具有Authentication的REST API。由于具有认证功能,因而,在JMeter中需要添加Http Authorization Manager。Http Authorization Manager是Config Element,添加后,需要配置认证信息,包括Base URL、Username、Password、Realm等。如下图所示:
注意,在配置Base URL时,应该设置为完整的URL(当然,也可以使用JMeter的变量)。
如果为了验证执行是否成功,建议添加View Result Tree这个Listener,因为它给出的结果信息中包括了Sampler result、Request与Response Data等信息,这样有利于我们甄别测试的Http Request是否正确,如果错误,是什么原因导致的。
- node实现watcher的困境
- Java基础-03(02).总结运算符、键盘录入、if语句
- Spring+SpringMVC+MyBatis+easyUI整合优化篇(十一)数据层优化-druid监控及慢sql记录
- python数据分析师面试题选
- Spring+SpringMVC+MyBatis+easyUI整合优化篇(九)数据层优化-jdbc连接池简述、druid简介
- webpack配置别名alias出现的错误匹配
- 在Java程序中处理数据库超时与死锁
- 如何用TensorFlow和TF-Slim实现图像标注、分类与分割
- Spring+SpringMVC+MyBatis+easyUI整合优化篇(六)easyUI与富文本编辑器UEditor整合
- 使用shell脚本查看数据库负载情况(第二篇)(r3笔记第92天)
- tensorflow LSTM + CTC实现端到端OCR
- Spring+SpringMVC+MyBatis+easyUI整合优化篇(七)图片上传功能
- 黑客比程序员牛在哪?
- oracle工具集初探(r4笔记第8天)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- spring之通过注解方式配置Bean(二)
- 【python-leetcode103-树的宽度遍历】二叉树的锯齿形层次遍历
- 图卷积网络(GCN)python实现
- hadoop伪分布式之配置yarn并运行MR程序(WordCount)
- 【python-leetcode637-树的宽度遍历】二叉树的层平均值
- graphSAGE的python实现
- 【python-leetcode111-树的宽度遍历】二叉树的最小深度
- 基于TypeScript封装Axios笔记(四)
- spring之泛型依赖注入
- 【python-leetcode113-树的深度遍历】路径总和Ⅱ
- spring之为什么要使用AOP(面向切面编程)?
- useContext更佳实践
- 【论文笔记】张航和李沐等提出:ResNeSt: Split-Attention Networks(ResNet改进版本)
- [前端]GOFLY项目-响应式登录页的设计和实现
- [GO] golang练习项目-gorm与mysql的增删查改操作