第 1 章 Web 端点的授权
Quarkus 包含可插拔 Web 安全层。当安全性处于活动状态时,系统会对所有 HTTP 请求执行权限检查,以确定它们是否应该继续。
如果路径受 quarkus.http.auth.
配置的限制,则使用 @PermitAll
不会打开路径。为确保特定路径可以访问,必须在 Quarkus 安全设置中进行适当的配置。
如果使用 Jakarta RESTful Web 服务,请考虑使用 quarkus.security.jaxrs.deny-unannotated-endpoints
或 quarkus.security.jaxrs.default-roles-allowed
来设置默认安全要求而不是 HTTP 路径级别匹配,因为注解可在单个端点上覆盖这些属性。
授权基于安全提供程序提供的用户角色。若要自定义这些角色,可以创建 SecurityIdentityAugmentor
,请参阅 安全身份自定义。
1.1. 使用配置进行授权
权限通过权限集在 Quarkus 配置中定义,各自为访问控制指定策略。
内置策略 | 描述 |
---|---|
| 此策略拒绝所有用户。 |
| 此策略允许所有用户。 |
| 此策略仅允许经过身份验证的用户。 |
您可以定义基于角色的策略,以允许具有特定角色的用户访问资源。
基于角色的策略示例
quarkus.http.auth.policy.role-policy1.roles-allowed=user,admin 1
quarkus.http.auth.policy.role-policy1.roles-allowed=user,admin 1
Copy to clipboardCopied- 1
- 它定义了一个基于角色的策略,允许用户拥有
用户和
admin
角色的用户。
您可以通过配置 application.properties
文件中定义的内置权限集来引用自定义策略,如下例所示:
策略配置示例
quarkus.http.auth.permission.permit1.paths=/public/* 1 quarkus.http.auth.permission.permit1.policy=permit quarkus.http.auth.permission.permit1.methods=GET quarkus.http.auth.permission.deny1.paths=/forbidden 2 quarkus.http.auth.permission.deny1.policy=deny quarkus.http.auth.permission.roles1.paths=/roles-secured/*,/other/*,/api/* 3 quarkus.http.auth.permission.roles1.policy=role-policy1
quarkus.http.auth.permission.permit1.paths=/public/* 1
quarkus.http.auth.permission.permit1.policy=permit
quarkus.http.auth.permission.permit1.methods=GET
quarkus.http.auth.permission.deny1.paths=/forbidden 2
quarkus.http.auth.permission.deny1.policy=deny
quarkus.http.auth.permission.roles1.paths=/roles-secured/*,/other/*,/api/* 3
quarkus.http.auth.permission.roles1.policy=role-policy1
Copy to clipboardCopied
上例中的具体路径模式 /forbidden
也保护 /forbidden/
路径。这样,在以下示例中 禁止
的端点通过 deny1
权限进行保护。
package org.acme.crud; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; @Path("/forbidden") public class ForbiddenResource { @GET public String forbidden() { 1 return "No!"; } }
package org.acme.crud;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
@Path("/forbidden")
public class ForbiddenResource {
@GET
public String forbidden() { 1
return "No!";
}
}
Copy to clipboardCopied- 1
- 为了保护
禁止
的端点,需要保护/forbidden
和/forbidden/
路径。
如果您需要允许访问 /forbidden/
路径,请添加具有更具体具体路径的新权限,如下例所示:
quarkus.http.auth.permission.permit1.paths=/forbidden/ 1 quarkus.http.auth.permission.permit1.policy=permit
quarkus.http.auth.permission.permit1.paths=/forbidden/ 1
quarkus.http.auth.permission.permit1.policy=permit
Copy to clipboardCopied- 1
/forbidden/
路径不受保护。
1.1.1. Custom HttpSecurityPolicy
有时,注册您自己的命名策略可能很有用。您可以通过创建实现 io.quarkus.vertx.http.runtime.security.HttpSecurityPolicy
接口的应用程序范围 CDI bean 来实现它,如下例所示:
import jakarta.enterprise.context.ApplicationScoped; import io.quarkus.security.identity.SecurityIdentity; import io.quarkus.vertx.http.runtime.security.HttpSecurityPolicy; import io.smallrye.mutiny.Uni; import io.vertx.ext.web.RoutingContext; @ApplicationScoped public class CustomNamedHttpSecPolicy implements HttpSecurityPolicy { @Override public Uni<CheckResult> checkPermission(RoutingContext event, Uni<SecurityIdentity> identity, AuthorizationRequestContext requestContext) { if (customRequestAuthorization(event)) { return CheckResult.permit(); } return CheckResult.deny(); } @Override public String name() { return "custom"; 1 } private static boolean customRequestAuthorization(RoutingContext event) { // here comes your own security check return !event.request().path().endsWith("denied"); } }
import jakarta.enterprise.context.ApplicationScoped;
import io.quarkus.security.identity.SecurityIdentity;
import io.quarkus.vertx.http.runtime.security.HttpSecurityPolicy;
import io.smallrye.mutiny.Uni;
import io.vertx.ext.web.RoutingContext;
@ApplicationScoped
public class CustomNamedHttpSecPolicy implements HttpSecurityPolicy {
@Override
public Uni<CheckResult> checkPermission(RoutingContext event, Uni<SecurityIdentity> identity,
AuthorizationRequestContext requestContext) {
if (customRequestAuthorization(event)) {
return CheckResult.permit();
}
return CheckResult.deny();
}
@Override
public String name() {
return "custom"; 1
}
private static boolean customRequestAuthorization(RoutingContext event) {
// here comes your own security check
return !event.request().path().endsWith("denied");
}
}
Copy to clipboardCopied- 1
- 命名的 HTTP 安全策略将仅应用到与
application.properties
路径匹配规则匹配的请求。
从配置文件引用的名为 HttpSecurityPolicy 的自定义示例
quarkus.http.auth.permission.custom1.paths=/custom/* quarkus.http.auth.permission.custom1.policy=custom 1
quarkus.http.auth.permission.custom1.paths=/custom/*
quarkus.http.auth.permission.custom1.policy=custom 1
Copy to clipboardCopied- 1
- 自定义策略名称必须与
io.quarkus.vertx.http.runtime.security.HttpSecurityPolicy.name
方法返回的值匹配。
或者,您可以将名为 HttpSecurityPolicy 的自定义绑定到带有 @AuthorizationPolicy
安全注释的 Jakarta REST 端点。
您还可以在每个请求上创建全局 HttpSecurityPolicy
。只需实施 io.quarkus.vertx.http.runtime.security.HttpSecurityPolicy.name
方法,使策略保持无处。
1.1.2. 将 @RequestScoped
Bean 注入 HttpSecurityPolicy
@RequestScoped
Bean 只能在 CDI 请求上下文 处于活跃状态时注入。上下文可以由用户激活,例如使用 @ActivateRequestContext
,但授权发生在 Quarkus 准备一些 @RequestScoped
Bean 之前发生。我们建议让 Quarkus 激活并为您准备 CDI 请求上下文。例如,请考虑您要从 Jakarta REST 上下文注入 bean 的情况,如 jakarta.ws.rs.core.UriInfo
bean。在这种情况下,您必须将 HttpSecurityPolicy
应用到 Jakarta REST 端点。这可以通过以下之一来实现:* 使用 @AuthorizationPolicy
安全注解。* 设置 quarkus.http.auth.permission.custom1.applies-to=jaxrs
配置属性。
1.1.3. 匹配路径和方法
权限集也可以将路径和方法指定为用逗号分开的列表。如果路径以 *
通配符结尾,它生成的查询与所有子路径匹配。否则,它会查询一个完全匹配,仅匹配该特定路径:
quarkus.http.auth.permission.permit1.paths=/public*,/css/*,/js/*,/robots.txt 1 quarkus.http.auth.permission.permit1.policy=permit quarkus.http.auth.permission.permit1.methods=GET,HEAD
quarkus.http.auth.permission.permit1.paths=/public*,/css/*,/js/*,/robots.txt 1
quarkus.http.auth.permission.permit1.policy=permit
quarkus.http.auth.permission.permit1.methods=GET,HEAD
Copy to clipboardCopied- 1
- 路径末尾的
*
通配符匹配零个或更多路径片段,但永远不会从/public
路径开始的任何单词。因此,类似/public-info
的路径与此模式不匹配。
1.1.4. 匹配路径而不是方法
如果请求根据路径匹配一个或多个权限集,则请求将被拒绝,但没有需要的方法。
根据前面的权限集,GET /public/foo
将与路径和方法匹配,因此允许。相反,POST /public/foo
将与路径匹配,而不是方法,因此被拒绝。
1.1.5. 匹配多个路径:最长路径胜出
匹配始终以 "longest path wins" 为基础完成。如果多个特定权限集匹配,则不考虑较少的权限集:
quarkus.http.auth.permission.permit1.paths=/public/* quarkus.http.auth.permission.permit1.policy=permit quarkus.http.auth.permission.permit1.methods=GET,HEAD quarkus.http.auth.permission.deny1.paths=/public/forbidden-folder/* quarkus.http.auth.permission.deny1.policy=deny
quarkus.http.auth.permission.permit1.paths=/public/*
quarkus.http.auth.permission.permit1.policy=permit
quarkus.http.auth.permission.permit1.methods=GET,HEAD
quarkus.http.auth.permission.deny1.paths=/public/forbidden-folder/*
quarkus.http.auth.permission.deny1.policy=deny
Copy to clipboardCopied
根据前面的权限集,GET /public/forbidden-folder/foo
将匹配两个权限集的路径。但是,因为较长的路径与 deny1
权限集的路径匹配,因此选择 deny1
,并且请求被拒绝。
在 root 路径权限前的 subPath 权限,因为 deny1
和 permit1
权限示例前面展示了。
此规则进一步加大了在 root 路径权限需要授权时,子路径权限允许访问公共资源的场景。
quarkus.http.auth.policy.user-policy.roles-allowed=user quarkus.http.auth.permission.roles.paths=/api/* quarkus.http.auth.permission.roles.policy=user-policy quarkus.http.auth.permission.public.paths=/api/noauth/* quarkus.http.auth.permission.public.policy=permit
quarkus.http.auth.policy.user-policy.roles-allowed=user
quarkus.http.auth.permission.roles.paths=/api/*
quarkus.http.auth.permission.roles.policy=user-policy
quarkus.http.auth.permission.public.paths=/api/noauth/*
quarkus.http.auth.permission.public.policy=permit
Copy to clipboardCopied1.1.6. 匹配多个子路径:到 *
通配符的前一个路径
前面的示例演示了,当路径结束带有 *
通配符时,匹配所有子路径。
此通配符也适用于路径的中间,代表单个路径段。它不能与其他路径片段字符混合;因此,路径分隔符始终包括 *
通配符,如 /public configured/about-us
路径中所示。
当多个路径模式与同一请求路径对应时,系统会选择前导到 *
通配符的最长子路径。在这种情况下,每个路径片段字符都比 *
通配符更为具体。
下面是一个简单的示例:
quarkus.http.auth.permission.secured.paths=/api/*/detail 1 quarkus.http.auth.permission.secured.policy=authenticated quarkus.http.auth.permission.public.paths=/api/public-product/detail 2 quarkus.http.auth.permission.public.policy=permit
quarkus.http.auth.permission.secured.paths=/api/*/detail 1
quarkus.http.auth.permission.secured.policy=authenticated
quarkus.http.auth.permission.public.paths=/api/public-product/detail 2
quarkus.http.auth.permission.public.policy=permit
Copy to clipboardCopied应测试使用配置进行授权保护的所有路径。使用多个通配符编写路径模式可能会非常繁琐。请确保路径按照预期授权。
在以下示例中,路径从最具体到最具体的路径排序:
请求路径 /one/two/three/four/five
匹配从最具体到最小特定路径的顺序
/one/two/three/four/five /one/two/three/four/* /one/two/three/*/five /one/two/three/*/* /one/two/*/four/five /one/*/three/four/five /*/two/three/four/five /*/two/three/*/five /*
/one/two/three/four/five
/one/two/three/four/*
/one/two/three/*/five
/one/two/three/*/*
/one/two/*/four/five
/one/*/three/four/five
/*/two/three/four/five
/*/two/three/*/five
/*
Copy to clipboardCopied
路径末尾的 *
通配符匹配零个或多个路径片段。*
通配符放置在其它任何位置,与一个路径段完全匹配。
1.1.7. 匹配多个路径:大多数特定方法胜出
当使用多个权限集注册路径时,权限集会明确指定与请求具有优先匹配的 HTTP 方法。在本实例中,只有请求方法与方法规格的权限集不匹配时,没有方法的权限集才会生效。
quarkus.http.auth.permission.permit1.paths=/public/* quarkus.http.auth.permission.permit1.policy=permit quarkus.http.auth.permission.permit1.methods=GET,HEAD quarkus.http.auth.permission.deny1.paths=/public/* quarkus.http.auth.permission.deny1.policy=deny
quarkus.http.auth.permission.permit1.paths=/public/*
quarkus.http.auth.permission.permit1.policy=permit
quarkus.http.auth.permission.permit1.methods=GET,HEAD
quarkus.http.auth.permission.deny1.paths=/public/*
quarkus.http.auth.permission.deny1.policy=deny
Copy to clipboardCopied
上述权限集显示 GET /public/foo
与这两个权限集的路径匹配。无论如何,它明确与 permit1
权限集的显式方法一致。因此,选择 permit1
,并且接受请求。
相反,PUT /public/foo
与 permit1
的方法权限不匹配。因此,deny1
被激活,从而导致请求拒绝。
1.1.8. 匹配多个路径和方法:win
有时,之前描述的规则允许同时将多个权限设置为 win。在这种情况下,请求继续,所有权限都必须允许访问权限。要实现此目的,两者必须指定方法或没有方法。特定于方法的匹配具有优先权。
quarkus.http.auth.policy.user-policy1.roles-allowed=user quarkus.http.auth.policy.admin-policy1.roles-allowed=admin quarkus.http.auth.permission.roles1.paths=/api/*,/restricted/* quarkus.http.auth.permission.roles1.policy=user-policy1 quarkus.http.auth.permission.roles2.paths=/api/*,/admin/* quarkus.http.auth.permission.roles2.policy=admin-policy1
quarkus.http.auth.policy.user-policy1.roles-allowed=user
quarkus.http.auth.policy.admin-policy1.roles-allowed=admin
quarkus.http.auth.permission.roles1.paths=/api/*,/restricted/*
quarkus.http.auth.permission.roles1.policy=user-policy1
quarkus.http.auth.permission.roles2.paths=/api/*,/admin/*
quarkus.http.auth.permission.roles2.policy=admin-policy1
Copy to clipboardCopied
在设置了上述权限集后,GET /api/foo
将匹配两个权限集的路径,需要 用户和
admin
角色。
1.1.9. 拒绝访问的配置属性
以下配置设置更改了基于角色的访问控制(RBAC)拒绝行为:
quarkus.security.jaxrs.deny-unannotated-endpoints=true|false
-
如果设置为 true,则默认对所有 Jakarta REST 端点访问。如果 Jakarta REST 端点没有安全注解,则默认为
@DenyAll
行为。这有助于您避免意外公开应该被保护的端点。默认值为false
。 quarkus.security.jaxrs.default-roles-allowed=role1,role2
-
定义未注解端点的默认角色要求。
**
角色是一个特殊角色,意味着任何经过身份验证的用户。这不能与deny-unannotated-endpoints
结合使用,因为deny
会生效。 quarkus.security.deny-unannotated-members=true|false
-
如果设置为 true,则拒绝所有没有安全注解的 CDI 方法和 Jakarta REST 端点的访问,而是在包含安全注解方法的类中定义。默认值为
false
。
1.1.10. 禁用权限
可在构建时禁用权限,并为每个声明的权限 启用
属性,例如:
quarkus.http.auth.permission.permit1.enabled=false quarkus.http.auth.permission.permit1.paths=/public/*,/css/*,/js/*,/robots.txt quarkus.http.auth.permission.permit1.policy=permit quarkus.http.auth.permission.permit1.methods=GET,HEAD
quarkus.http.auth.permission.permit1.enabled=false
quarkus.http.auth.permission.permit1.paths=/public/*,/css/*,/js/*,/robots.txt
quarkus.http.auth.permission.permit1.policy=permit
quarkus.http.auth.permission.permit1.methods=GET,HEAD
Copy to clipboardCopied
可以使用系统属性或环境变量在运行时重新启用权限,如: -Dquarkus.http.auth.permission.permit1.enabled=true
。
1.1.11. 权限路径和 HTTP 根路径
quarkus.http.root-path
配置属性会更改 http 端点上下文路径。
默认情况下,quarkus.http.root-path
会自动添加到配置的权限路径中,然后不使用正斜杠,例如:
quarkus.http.auth.permission.permit1.paths=public/*,css/*,js/*,robots.txt
quarkus.http.auth.permission.permit1.paths=public/*,css/*,js/*,robots.txt
Copy to clipboardCopied这个配置等同于:
quarkus.http.auth.permission.permit1.paths=${quarkus.http.root-path}/public/*,${quarkus.http.root-path}/css/*,${quarkus.http.root-path}/js/*,${quarkus.http.root-path}/robots.txt
quarkus.http.auth.permission.permit1.paths=${quarkus.http.root-path}/public/*,${quarkus.http.root-path}/css/*,${quarkus.http.root-path}/js/*,${quarkus.http.root-path}/robots.txt
Copy to clipboardCopied
前导斜杠会改变配置的权限路径的解释方式。配置的 URL 以原样使用,如果 quarkus.http.root-path
的值改变,则路径不会被调整。
Example:
quarkus.http.auth.permission.permit1.paths=/public/*,css/*,js/*,robots.txt
quarkus.http.auth.permission.permit1.paths=/public/*,css/*,js/*,robots.txt
Copy to clipboardCopied
此配置仅影响由固定或静态 URL /public
提供的资源,如果 quarkus.http.root-path
已设置为除 /
以外的其他内容,则它可能与您的应用程序资源不匹配。
如需更多信息,请参阅 Quarkus 中的路径解析。
1.1.12. 映射 SecurityIdentity
角色
获奖基于角色的策略可将 SecurityIdentity
角色映射到特定于部署的角色。这些角色随后通过使用 @RolesAllowed
注释应用到端点授权。
quarkus.http.auth.policy.admin-policy1.roles.admin=Admin1 1 quarkus.http.auth.permission.roles1.paths=/* 2 quarkus.http.auth.permission.roles1.policy=admin-policy1
quarkus.http.auth.policy.admin-policy1.roles.admin=Admin1 1
quarkus.http.auth.permission.roles1.paths=/* 2
quarkus.http.auth.permission.roles1.policy=admin-policy1
Copy to clipboardCopied
如果您只需要将 SecurityIdentity
角色映射到特定于部署的角色,无论路径是什么,您也可以执行此操作:
quarkus.http.auth.roles-mapping.admin=Admin1 1 2
quarkus.http.auth.roles-mapping.admin=Admin1 1 2
Copy to clipboardCopied