1.权限验证
Basic Authentication(基本验证)
注册验证
install(Authentication) {
basic("auth-basic") {
// 验证失败返回的消息
realm = "you don't have authority"
// validate 验证
validate { credentials ->
// credentials.name 用户名
if (credentials.name =="admin" && credentials.password =="123" ) {
UserIdPrincipal(credentials.name)
} else {
null
}
}
}
}
请求使用
当客户端没有在请求头中 携带 Authorization
的验证信息时,服务端会在响应头中携带 WWW-Authenticate
,并返回状态码401,告诉用户Unauthorized,如下:
WWW-Authenticate:Basic realm="you don't have authority", charset=UTF-8
客户端在请求头中携带了 Authorization
的验证信息时,服务端会在validate中验证权限是否通过,如果通过则 返回UserIdPrincipal
,否则返回null,客户端可以使用Base64对用户名和密码加密:
# 用户名密码格式: 用户名:密码 例如 admin:123 使用base64加密后 就是 YWRtaW46MTIz
# Basic则指明使用哪一种验证方式
Authorization:Basic emhhbnNnYW46MTIz
然后使用路由,我们让get请求不需要验证,post需要。
routing {
route("/test") {
get {
call.respondText("Hello,哈哈哈")
}
authenticate("auth-basic") {
post {
call.respondText("Hello, ${call.principal<UserIdPrincipal>()?.name}!")
}
}
}
}
这里使用post测试
Form Authentication(表单验证)
表单验证的大致流程就是,客户端发送请求,服务端返回给客户端一个表单,填写完成后路由到验证请求进行验证。
注册验证
install(Authentication) {
form("auth-form") {
// 对应表单name 的值
userParamName = "username"
passwordParamName = "password"
validate { credentials ->
if (credentials.name == "admin" && credentials.password == "123") {
UserIdPrincipal(credentials.name)
} else {
null
}
}
}
}
请求使用
首先 让客户端请求返回表单验证的地址 http://0.0.0.0:8087/authority,后端返回表单代码:
route("/authority") {
get {
call.respondHtml(HttpStatusCode.OK) {
body {
form {
action = "/login"
encType = FormEncType.applicationXWwwFormUrlEn
// 注意 这里必须是post请求
method = FormMethod.post
div {
"User:"
}
div {
input {
type = InputType.text
name = "username"
}
}
div {
"Password:"
}
div {
input {
type = InputType.text
name = "password"
}
}
div {
input {
type = InputType.submit
value = "Login"
}
}
}
}
}
}
}
然后会弹出输入框,输入用户名密码验证
当跳转到login
时,会验证 username和password
route("/login") {
authenticate("auth-form") {
// 注意 这里必须是post请求
post {
call.respondText("Hello, ${call.principal<UserIdPrincipal>()?.name}!")
}
}
}
Json Web Token
jwt的大致流程就是 第一次登录 请求成功后,服务端会生成一个token 给客户端,客户端可以在请求的时候请求头携带token访问被保护的资源
注册验证
val secret = globalEnvironment.config.getMandatoryString("jwt.secret")
val issuer = globalEnvironment.config.getMandatoryString("jwt.issuer")
val audience = globalEnvironment.config.getMandatoryString("jwt.audience")
val myRealm = globalEnvironment.config.getMandatoryString("jwt.realm")
install(Authentication) {
jwt("auth-jwt") {
// 验证token
realm=myRealm
verifier(JWT
.require(Algorithm.HMAC256(secret))
.withAudience(audience)
.withIssuer(issuer)
.build()
)
validate {
credential->
if (credential.payload.getClaim("username").asString() != "") {
JWTPrincipal(credential.payload)
} else {
null
}
}
}
}
访问登录接口获取token
routing {
post("/jwt/login") {
val user = JSON.parseObject(call.receiveText())
val token = JWT.create()
.withAudience(audience)
.withIssuer(issuer)
.withClaim("username", user["username"].toString())
.withExpiresAt(Date(System.currentTimeMillis() + 6000000))
.sign(Algorithm.HMAC256(secret))
call.respond(mapOf("token" to token))
}
}
访问被保护资源验证
authenticate("auth-jwt") {
get("/resources"){
val principal = call.principal<JWTPrincipal>()
val username = principal!!.payload.getClaim("username").asString()
val expiresAt = principal.expiresAt?.time?.minus(System.currentTimeMillis())
call.respondText("Hello, $username! Token is expired at $expiresAt ms.")
}
}
postman请求
请求头中携带格式
Authorization:Bearer token字符串
2.日志
使用 CallLogging 可以起到类似于 java aop切面编程的作用
使用如下
fun Application.configureLog() {
install(CallLogging) {
// 日至等级
level = Level.INFO
// 过滤请求
filter { call ->
println(call.request.path())
call.request.path().contains("log")
}
// 自定义日志消息
format { call ->
runBlocking {
val uri = call.request.path()
val status = call.response.status()
val httpMethod = call.request.httpMethod.value
val params = call.request.queryParameters.toMap().entries.associate { it.key to it.value[0] }.toString()
val bodyParams = call.receiveText()
"path:$uri,Method:$httpMethod,params:$bodyParams,responseStatus:$status"
}
}
}
}
标签:name,val,验证,ktor,call,credentials,请求
From: https://www.cnblogs.com/wlstudy09/p/16720498.html