The English version of quarkus.io is the official project site. Translated sites are community supported on a best-effort basis.

Authorize web endpoints

Quarkus has an integrated pluggable web security layer. If security is enabled, all HTTP requests will have a permission check performed to make sure they are allowed to continue. This means you cannot use @PermitAll to open a path if the path is blocked by the quarkus.http.auth. configuration.

If you are using JAX-RS, consider using quarkus.security.jaxrs.deny-unannotated-endpoints or quarkus.security.jaxrs.default-roles-allowed to set default security requirements instead of HTTP path-level matching because annotations can override these properties on an individual endpoint.

Authorization is based on user roles that the security provider provides. To customize these roles, a SecurityIdentityAugmentor can be created, see Security Identity Customization.

Authorization using configuration

Permissions are defined in the Quarkus configuration using permission sets, with each permission set specifying a policy for access control.

Table 1. Quarkus policies summary

Built-in policy

描述

deny

This policy denies all users.

permit

This policy permits all users.

authenticated

This policy permits only authenticated users.

You can define role-based policies that allow users with specified roles to access the resources.

Example of a role-based policy
quarkus.http.auth.policy.role-policy1.roles-allowed=user,admin                  (1)
1 This defines a role-based policy that allows users with the user and admin roles. Such a custom policy can be referenced by permission sets just like the built-in ones, as shown in the example below.

Permission sets are defined in application.properties as follows:

Example of policy configuration
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
1 This permission references the default permit built-in policy to allow GET methods to /public. In this case, the demonstrated setting would not affect this example because this request is allowed anyway.
2 这个权限引用了内置的 deny 策略来作用于 /forbidden 。这是一个精确的路径匹配,因为它没有以 * 结尾。
3 This is a permission set that references the previously defined policy. roles1 is an example name; you can call the permission sets whatever you want.

Matching on paths and methods

Permission sets can also specify paths and methods as a comma-separated list. If a path ends with the * wildcard, the query it generates matches all sub-paths. Otherwise, it queries for an exact match and will only match that specific path:

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

Matching a path but not a method

The request is rejected if a request matches one or more permission sets based on the path but does not match any due to method requirements.

Given the above permission set, GET /public/foo would match both the path and method and thus be allowed, whereas POST /public/foo would match the path but not the method and would therefore be rejected.

匹配多条路径:最长的路径获胜

Matching is always done on the "longest path wins" basis. Less specific permission sets are not considered if a more specific one has been matched:

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
Given the above permission set, GET /public/forbidden-folder/foo would match both permission sets' paths, but because it matches the deny1 permission set’s path on a longer match, deny1 will be chosen, and the request will be rejected.

Subpath permissions always win against the root path permissions, as explained above in the deny1 versus permit1 permission example. Here is another example showing subpath permission allowing a public resource access with the root path permission requiring the authorization:

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

匹配多条路径:最具体的方法获胜

When a path is registered with multiple permission sets, the permission sets that explicitly specify an HTTP method that matches the request will take precedence. In this instance, the permission sets without methods will only come into effect if the request method does not match permission sets with the method specification.

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

Given the above permission set, GET /public/foo would match the paths of both permission sets, but because it fits the explicit method of the permit1 permission set, permit1 is chosen, and the request is accepted.

PUT /public/foo, on the other hand, will not match the method permissions of permit1, so deny1 will be activated and reject the request.

匹配多条路径和方法:双赢

Sometimes, the previously described rules allow multiple permission sets to win at the same time. In that case, for the request to proceed, all the permissions must allow access. Note that for this to happen, both have to either have specified the method or have no method. Method-specific matches take precedence.

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
Given the above permission set, GET /api/foo would match both permission sets' paths, requiring both the user and admin roles.

Configuration properties to deny access

The following configuration settings alter the role-based access control (RBAC) denying behavior:

quarkus.security.jaxrs.deny-unannotated-endpoints=true|false

If set to true, access is denied for all JAX-RS endpoints by default. If a JAX-RS endpoint does not have any security annotations, it defaults to the @DenyAll behavior. This is useful to ensure you cannot accidentally expose an endpoint that is supposed to be secured. Defaults to false.

quarkus.security.jaxrs.default-roles-allowed=role1,role2

Defines the default role requirements for unannotated endpoints. The ** role is a special role that means any authenticated user. This cannot be combined with deny-unannotated-endpoints, as deny takes the effect instead.

quarkus.security.deny-unannotated-members=true|false
  • 如果设置为 "true",所有没有加安全注解但被定义在包含安全注解的方法的类中的CDI方法和JAX-RS节点的访问将被拒绝。默认为 false

禁用权限

Permissions can be disabled at build time with an enabled property for each declared permission, such as:

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

Permissions can be reenabled at runtime with a system property or environment variable, such as: -Dquarkus.http.auth.permission.permit1.enabled=true.

Permission paths and HTTP root path

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=${quarkus.http.root-path}/public/*,${quarkus.http.root-path}/css/*,${quarkus.http.root-path}/js/*,${quarkus.http.root-path}/robots.txt

所有前置的斜杠将改变配置的权限路径的解释方式。配置的URL将按原样使用,并且如果 quarkus.http.root-path 的值改变后路径将不会被调整。例如:

quarkus.http.auth.permission.permit1.paths=/public/*,css/*,js/*,robots.txt

此配置将只影响从固定/静态URL /public 提供的资源,如果 quarkus.http.root-path 被设置为其他的 / ,那么它可能与您的应用程序资源不匹配。

更多信息见 Quarkus中的路径解析

Authorization using annotations

Quarkus comes with built-in security to allow for Role-Based Access Control (RBAC) based on the common security annotations @RolesAllowed, @DenyAll, @PermitAll on REST endpoints and CDI beans.

Table 2. Quarkus annotation types summary

Annotation type

描述

@DenyAll

Specifies that no security roles are allowed to invoke the specified methods.

@PermitAll

Specifies that all security roles are allowed to invoke the specified methods.

@PermitAll lets everybody in even without authentication.

@RolesAllowed

Specifies the list of security roles permitted to access methods in an application.

As an equivalent to @RolesAllowed("**"), Quarkus also provides the io.quarkus.security.Authenticated annotation that permits any authenticated user to access the resource.

SubjectExposingResource Example featured in this chapter demonstrates an endpoint that uses both JAX-RS and Common Security annotations to describe and secure its endpoints.

SubjectExposingResource Example
import java.security.Principal;

import javax.annotation.security.DenyAll;
import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.SecurityContext;

@Path("subject")
public class SubjectExposingResource {

    @GET
    @Path("secured")
    @RolesAllowed("Tester") (1)
    public String getSubjectSecured(@Context SecurityContext sec) {
        Principal user = sec.getUserPrincipal(); (2)
        String name = user != null ? user.getName() : "anonymous";
        return name;
    }

    @GET
    @Path("unsecured")
    @PermitAll (3)
    public String getSubjectUnsecured(@Context SecurityContext sec) {
        Principal user = sec.getUserPrincipal(); (4)
        String name = user != null ? user.getName() : "anonymous";
        return name;
    }

    @GET
    @Path("denied")
    @DenyAll (5)
    public String getSubjectDenied(@Context SecurityContext sec) {
        Principal user = sec.getUserPrincipal();
        String name = user != null ? user.getName() : "anonymous";
        return name;
    }
}
1 The /subject/secured endpoint requires an authenticated user with the granted "Tester" role through the use of the @RolesAllowed("Tester") annotation.
2 该节点通过 JAX-RS SecurityContext 获取用户principal。对于受保护节点它将永不为null。
3 /subject/unsecured 节点通过使用 @PermitAll 注解来允许未认证的访问。
4 The call to obtain the user principal returns null if the caller is unauthenticated and non-null if the caller is authenticated.
5 The /subject/denied endpoint declares the @DenyAll annotation, thus disallowing all direct access to it as a REST method, regardless of the user calling it. The method is still invokable internally by other methods in this class.
Please refer to the Proactive Authentication section of the Built-In Authentication Support guide if you plan to use standard security annotations on the IO thread.

The @RolesAllowed annotation value supports Property Expressions including default values and nested Property Expressions. Configuration properties used with the annotation are resolved at runtime.

Table 3. Annotation value examples

Annotation

Value explanation

@RolesAllowed("${admin-role}")

The endpoint will allow users with the role denoted by the value of the admin-role property.

@RolesAllowed("${tester.group}-${tester.role}")

An example showing that the value can contain multiple variables.

@RolesAllowed("${customer:User}")

A default value demonstration. The required role will be denoted by the value of the customer property, but if that property is not specified, a role named User will be required as a default.

Example of a property expressions usage in the @RolesAllowed annotation
admin=Administrator
tester.group=Software
tester.role=Tester
%prod.secured=User
%dev.secured=**
import java.security.Principal;

import javax.annotation.security.DenyAll;
import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.SecurityContext;

@Path("subject")
public class SubjectExposingResource {

    @GET
    @Path("admin")
    @RolesAllowed("${admin}") (1)
    public String getSubjectSecuredAdmin(@Context SecurityContext sec) {
        Principal user = sec.getUserPrincipal();
        String name = user != null ? user.getName() : "anonymous";
        return name;
    }

    @GET
    @Path("software-tester")
    @RolesAllowed("${tester.group}-${tester.role}") (2)
    public String getSubjectSoftwareTester(@Context SecurityContext sec) {
        Principal user = sec.getUserPrincipal();
        String name = user != null ? user.getName() : "anonymous";
        return name;
    }

    @GET
    @Path("user")
    @RolesAllowed("${customer:User}") (3)
    public String getSubjectUser(@Context SecurityContext sec) {
        Principal user = sec.getUserPrincipal();
        String name = user != null ? user.getName() : "anonymous";
        return name;
    }

    @GET
    @Path("secured")
    @RolesAllowed("${secured}") (4)
    public String getSubjectSecured(@Context SecurityContext sec) {
        Principal user = sec.getUserPrincipal();
        String name = user != null ? user.getName() : "anonymous";
        return name;
    }
}
1 The @RolesAllowed annotation value is set to the value of Administrator.
2 This /subject/software-tester endpoint requires an authenticated user that has been granted the role "Software-Tester". It is possible to use multiple expressions in the role definition.
3 This /subject/user endpoint requires an authenticated user that has been granted the role "User" through the use of the @RolesAllowed("${customer:User}") annotation, as we did not set the configuration property customer.
4 This /subject/secured endpoint requires an authenticated user that has been granted the role User in production but allows any authenticated user in development mode.