moonback adapter for moon-token: per-route auth middleware, request principal in userdata, and route-policy wiring for the moonback web framework
Dependencies
moon add mldong/moon-token mldong/moon-token-store mldong/moon-token-moonback
moon add moonbitlang/moonback moonbitlang/asyncstruct MbPerms {}
///|
pub impl @port.PermissionProvider for MbPerms with fn get_permissions(
_self,
login_id,
_device,
) {
if login_id == "admin" { ["sys:user:save"] } else { [] }
}
///|
pub impl @port.PermissionProvider for MbPerms with fn get_roles(
_self,
_login_id,
_device,
) {
["user"]
}
///|
pub impl @port.PermissionProvider for MbPerms with fn is_super_admin(
_self,
_login_id,
_device,
) {
false
}
pub MbPerms with @port.PermissionProvider::{
get_permissions,
get_roles,
is_super_admin,
}
///|
fn mb_auth(realm : String) -> @app.TokenAuth[@mem.MemoryStore, MbPerms] {
@app.TokenAuth::new(
realm,
@app.TokenConfig::default(),
@mem.MemoryStore::new(realm),
MbPerms::{},
@style.opaque_style(),
)
}
///|
let mb_save : @mb.Handler = async fn(request, responder) {
let who = match @mbguard.principal_of(request) {
None => "(豁免路由没有主体)"
Some(p) => p.login_id
}
responder.send_text("saved by " + who)
}
///|
let mb_ping : @mb.Handler = async fn(_request, responder) {
responder.send_text("public")
}
///|
async fn mb_wiring(realm : String) -> Unit {
let auth = mb_auth(realm)
let policy = (@guard.RoutePolicy::new()).exempt("/public/**").rule(
@guard.RouteRule::make("/sys/user/save", ["sys:user:save"]),
)
let g = @mbguard.Guard::new(auth, policy)
let root = @mb.Module((ctx) => {
ctx.get("/public/ping", mb_ping) catch {
_ => fail("/public/ping 注册失败")
}
g.get(ctx, "/sys/user/save", mb_save) catch {
_ => fail("/sys/user/save 注册失败")
}
})
let app = @mb.App(root)
// 这里只建路由表,不 listen:真起服务器见 `examples/cmd/moonback-demo`
app.close()
let token = auth.login("admin", device="pc").token
let fns : @guard.RequestFns = {
path: fn() { "/sys/user/save" },
header: fn(_) { Some(token) },
}
match @mbguard.decide(auth, policy, fns) {
None => fail("够权限应有主体")
Some(p) => assert_eq(p.login_id, "admin")
}
// 没带凭证的那一趟必须精确报 AbsentToken,状态码 401
let absent : @guard.RequestFns = {
path: fn() { "/sys/user/save" },
header: fn(_) { None },
}
let why = try {
let _ = @mbguard.decide(auth, policy, absent)
"没抛"
} catch {
err => err.message()
}
assert_eq(why, "not login: AbsentToken")
assert_eq(@mbguard.status_of(@port.NotLogin(@port.AbsentToken)), 401)
}
///|
async test "README 这条链真跑:建路由表 + 判决 + 状态码" {
mb_wiring("readme-mb")
}Install
Download zipmoonback adapter for moon-token: per-route auth middleware, request principal in userdata, and route-policy wiring for the moonback web framework
Dependencies