parent
eceb9ed479
commit
7236f2c5f2
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 119 KiB |
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 121 KiB |
|
@ -48,7 +48,8 @@
|
|||
*** xref:servlet/authentication/events.adoc[Authentication Events]
|
||||
** xref:servlet/authorization/index.adoc[Authorization]
|
||||
*** xref:servlet/authorization/architecture.adoc[Authorization Architecture]
|
||||
*** xref:servlet/authorization/authorize-requests.adoc[Authorize HTTP Requests]
|
||||
*** xref:servlet/authorization/authorize-http-requests.adoc[Authorize HTTP Requests]
|
||||
*** xref:servlet/authorization/authorize-requests.adoc[Authorize HTTP Requests with FilterSecurityInterceptor]
|
||||
*** xref:servlet/authorization/expression-based.adoc[Expression-Based Access Control]
|
||||
*** xref:servlet/authorization/secure-objects.adoc[Secure Object Implementations]
|
||||
*** xref:servlet/authorization/method-security.adoc[Method Security]
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
== Authorities
|
||||
xref:servlet/authentication/architecture.adoc#servlet-authentication-authentication[`Authentication`], discusses how all `Authentication` implementations store a list of `GrantedAuthority` objects.
|
||||
These represent the authorities that have been granted to the principal.
|
||||
The `GrantedAuthority` objects are inserted into the `Authentication` object by the `AuthenticationManager` and are later read by ``AccessDecisionManager``s when making authorization decisions.
|
||||
The `GrantedAuthority` objects are inserted into the `Authentication` object by the `AuthenticationManager` and are later read by either the `AuthorizationManager` when making authorization decisions.
|
||||
|
||||
`GrantedAuthority` is an interface with only one method:
|
||||
|
||||
|
@ -19,25 +19,219 @@ String getAuthority();
|
|||
|
||||
----
|
||||
|
||||
This method allows
|
||||
``AccessDecisionManager``s to obtain a precise `String` representation of the `GrantedAuthority`.
|
||||
By returning a representation as a `String`, a `GrantedAuthority` can be easily "read" by most ``AccessDecisionManager``s.
|
||||
This method allows ``AuthorizationManager``s to obtain a precise `String` representation of the `GrantedAuthority`.
|
||||
By returning a representation as a `String`, a `GrantedAuthority` can be easily "read" by most ``AuthorizationManager``s and ``AccessDecisionManager``s.
|
||||
If a `GrantedAuthority` cannot be precisely represented as a `String`, the `GrantedAuthority` is considered "complex" and `getAuthority()` must return `null`.
|
||||
|
||||
An example of a "complex" `GrantedAuthority` would be an implementation that stores a list of operations and authority thresholds that apply to different customer account numbers.
|
||||
Representing this complex `GrantedAuthority` as a `String` would be quite difficult, and as a result the `getAuthority()` method should return `null`.
|
||||
This will indicate to any `AccessDecisionManager` that it will need to specifically support the `GrantedAuthority` implementation in order to understand its contents.
|
||||
This will indicate to any `AuthorizationManager` that it will need to specifically support the `GrantedAuthority` implementation in order to understand its contents.
|
||||
|
||||
Spring Security includes one concrete `GrantedAuthority` implementation, `SimpleGrantedAuthority`.
|
||||
This allows any user-specified `String` to be converted into a `GrantedAuthority`.
|
||||
All ``AuthenticationProvider``s included with the security architecture use `SimpleGrantedAuthority` to populate the `Authentication` object.
|
||||
|
||||
|
||||
[[authz-pre-invocation]]
|
||||
== Pre-Invocation Handling
|
||||
Spring Security provides interceptors which control access to secure objects such as method invocations or web requests.
|
||||
A pre-invocation decision on whether the invocation is allowed to proceed is made by the `AccessDecisionManager`.
|
||||
|
||||
=== The AuthorizationManager
|
||||
`AuthorizationManager` supersedes both <<authz-legacy-note,`AccessDecisionManager` and `AccessDecisionVoter`>>.
|
||||
|
||||
Applications that customize an `AccessDecisionManager` or `AccessDecisionVoter` are encouraged to <<authz-voter-adaptation,change to using `AuthorizationManager`>>.
|
||||
|
||||
``AuthorizationManager``s are called by the xref:servlet/authorization/authorize-http-requests.adoc[`AuthorizationFilter`] and are responsible for making final access control decisions.
|
||||
The `AuthorizationManager` interface contains two methods:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
AuthorizationDecision check(Supplier<Authentication> authentication, Object secureObject);
|
||||
|
||||
default AuthorizationDecision verify(Supplier<Authentication> authentication, Object secureObject)
|
||||
throws AccessDeniedException {
|
||||
// ...
|
||||
}
|
||||
----
|
||||
|
||||
The ``AuthorizationManager``'s `check` method is passed all the relevant information it needs in order to make an authorization decision.
|
||||
In particular, passing the secure `Object` enables those arguments contained in the actual secure object invocation to be inspected.
|
||||
For example, let's assume the secure object was a `MethodInvocation`.
|
||||
It would be easy to query the `MethodInvocation` for any `Customer` argument, and then implement some sort of security logic in the `AuthorizationManager` to ensure the principal is permitted to operate on that customer.
|
||||
Implementations are expected to return a positive `AuthorizationDecision` if access is granted, negative `AuthorizationDecision` if access is denied, and a null `AuthorizationDecision` when abstaining from making a decision.
|
||||
|
||||
`verify` calls `check` and subsequently throws an `AccessDeniedException` in the case of a negative `AuthorizationDecision`.
|
||||
|
||||
[[authz-delegate-authorization-manager]]
|
||||
=== Delegate-based AuthorizationManager Implementations
|
||||
Whilst users can implement their own `AuthorizationManager` to control all aspects of authorization, Spring Security ships with a delegating `AuthorizationManager` that can collaborate with individual ``AuthorizationManager``s.
|
||||
|
||||
`RequestMatcherDelegatingAuthorizationManager` will match the request with the most appropriate delegate `AuthorizationManager`.
|
||||
For method security, you can use `AuthorizationManagerBeforeMethodInterceptor` and `AuthorizationManagerAfterMethodInterceptor`.
|
||||
|
||||
<<authz-authorization-manager-implementations>> illustrates the relevant classes.
|
||||
|
||||
[[authz-authorization-manager-implementations]]
|
||||
.Authorization Manager Implementations
|
||||
image::{figures}/authorizationhierarchy.png[]
|
||||
|
||||
Using this approach, a composition of `AuthorizationManager` implementations can be polled on an authorization decision.
|
||||
|
||||
[[authz-authority-authorization-manager]]
|
||||
==== AuthorityAuthorizationManager
|
||||
The most common `AuthorizationManager` provided with Spring Security is `AuthorityAuthorizationManager`.
|
||||
It is configured with a given set of authorities to look for on the current `Authentication`.
|
||||
It will return positive `AuthorizationDecision` should the `Authentication` contain any of the configured authorities.
|
||||
It will return a negative `AuthorizationDecision` otherwise.
|
||||
|
||||
[[authz-authenticated-authorization-manager]]
|
||||
==== AuthenticatedAuthorizationManager
|
||||
Another manager is the `AuthenticatedAuthorizationManager`.
|
||||
It can be used to differentiate between anonymous, fully-authenticated and remember-me authenticated users.
|
||||
Many sites allow certain limited access under remember-me authentication, but require a user to confirm their identity by logging in for full access.
|
||||
|
||||
[[authz-custom-authorization-manager]]
|
||||
==== Custom Authorization Managers
|
||||
Obviously, you can also implement a custom `AuthorizationManager` and you can put just about any access-control logic you want in it.
|
||||
It might be specific to your application (business-logic related) or it might implement some security administration logic.
|
||||
For example, you can create an implementation that can query Open Policy Agent or your own authorization database.
|
||||
|
||||
[TIP]
|
||||
You'll find a https://spring.io/blog/2009/01/03/spring-security-customization-part-2-adjusting-secured-session-in-real-time[blog article] on the Spring web site which describes how to use the legacy `AccessDecisionVoter` to deny access in real-time to users whose accounts have been suspended.
|
||||
You can achieve the same outcome by implementing `AuthorizationManager` instead.
|
||||
|
||||
[[authz-voter-adaptation]]
|
||||
== Adapting AccessDecisionManager and AccessDecisionVoters
|
||||
|
||||
Previous to `AuthorizationManager`, Spring Security published <<authz-legacy-note,`AccessDecisionManager` and `AccessDecisionVoter`>>.
|
||||
|
||||
In some cases, like migrating an older application, it may be desirable to introduce an `AuthorizationManager` that invokes an `AccessDecisionManager` or `AccessDecisionVoter`.
|
||||
|
||||
To call an existing `AccessDecisionManager`, you can do:
|
||||
|
||||
.Adapting an AccessDecisionManager
|
||||
====
|
||||
.Java
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@Component
|
||||
public class AccessDecisionManagerAuthorizationManagerAdapter implements AuthorizationManager {
|
||||
private final AccessDecisionManager accessDecisionManager;
|
||||
private final SecurityMetadataSource securityMetadataSource;
|
||||
|
||||
@Override
|
||||
public AuthorizationDecision check(Supplier<Authentication> authentication, Object object) {
|
||||
try {
|
||||
Collection<ConfigAttributes> attributes = this.securityMetadataSource.getAttributes(object);
|
||||
this.accessDecisionManager.decide(authentication.get(), object, attributes);
|
||||
return new AuthorizationDecision(true);
|
||||
} catch (AccessDeniedException ex) {
|
||||
return new AuthorizationDecision(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void verify(Supplier<Authentication> authentication, Object object) {
|
||||
Collection<ConfigAttributes> attributes = this.securityMetadataSource.getAttributes(object);
|
||||
this.accessDecisionManager.decide(authentication.get(), object, attributes);
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
And then wire it into your `SecurityFilterChain`.
|
||||
|
||||
Or to only call an `AccessDecisionVoter`, you can do:
|
||||
|
||||
.Adapting an AccessDecisionVoter
|
||||
====
|
||||
.Java
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@Component
|
||||
public class AccessDecisionVoterAuthorizationManagerAdapter implements AuthorizationManager {
|
||||
private final AccessDecisionVoter accessDecisionVoter;
|
||||
private final SecurityMetadataSource securityMetadataSource;
|
||||
|
||||
@Override
|
||||
public AuthorizationDecision check(Supplier<Authentication> authentication, Object object) {
|
||||
Collection<ConfigAttributes> attributes = this.securityMetadataSource.getAttributes(object);
|
||||
int decision = this.accessDecisionVoter.vote(authentication.get(), object, attributes);
|
||||
switch (decision) {
|
||||
case ACCESS_GRANTED:
|
||||
return new AuthorizationDecision(true);
|
||||
case ACCESS_DENIED:
|
||||
return new AuthorizationDecision(false);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
And then wire it into your `SecurityFilterChain`.
|
||||
|
||||
[[authz-hierarchical-roles]]
|
||||
== Hierarchical Roles
|
||||
It is a common requirement that a particular role in an application should automatically "include" other roles.
|
||||
For example, in an application which has the concept of an "admin" and a "user" role, you may want an admin to be able to do everything a normal user can.
|
||||
To achieve this, you can either make sure that all admin users are also assigned the "user" role.
|
||||
Alternatively, you can modify every access constraint which requires the "user" role to also include the "admin" role.
|
||||
This can get quite complicated if you have a lot of different roles in your application.
|
||||
|
||||
The use of a role-hierarchy allows you to configure which roles (or authorities) should include others.
|
||||
An extended version of Spring Security's `RoleVoter`, `RoleHierarchyVoter`, is configured with a `RoleHierarchy`, from which it obtains all the "reachable authorities" which the user is assigned.
|
||||
A typical configuration might look like this:
|
||||
|
||||
.Hierarchical Roles Configuration
|
||||
====
|
||||
.Java
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@Bean
|
||||
AccessDecisionVoter hierarchyVoter() {
|
||||
RoleHierarchy hierarchy = new RoleHierarchyImpl();
|
||||
hierarchy.setHierarchy("ROLE_ADMIN > ROLE_STAFF\n" +
|
||||
"ROLE_STAFF > ROLE_USER\n" +
|
||||
"ROLE_USER > ROLE_GUEST");
|
||||
return new RoleHierarcyVoter(hierarchy);
|
||||
}
|
||||
----
|
||||
|
||||
.Xml
|
||||
[source,java,role="secondary"]
|
||||
----
|
||||
|
||||
<bean id="roleVoter" class="org.springframework.security.access.vote.RoleHierarchyVoter">
|
||||
<constructor-arg ref="roleHierarchy" />
|
||||
</bean>
|
||||
<bean id="roleHierarchy"
|
||||
class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
|
||||
<property name="hierarchy">
|
||||
<value>
|
||||
ROLE_ADMIN > ROLE_STAFF
|
||||
ROLE_STAFF > ROLE_USER
|
||||
ROLE_USER > ROLE_GUEST
|
||||
</value>
|
||||
</property>
|
||||
</bean>
|
||||
----
|
||||
====
|
||||
|
||||
Here we have four roles in a hierarchy `ROLE_ADMIN => ROLE_STAFF => ROLE_USER => ROLE_GUEST`.
|
||||
A user who is authenticated with `ROLE_ADMIN`, will behave as if they have all four roles when security constraints are evaluated against an `AuthorizationManager` adapted to call the above `RoleHierarchyVoter`.
|
||||
The `>` symbol can be thought of as meaning "includes".
|
||||
|
||||
Role hierarchies offer a convenient means of simplifying the access-control configuration data for your application and/or reducing the number of authorities which you need to assign to a user.
|
||||
For more complex requirements you may wish to define a logical mapping between the specific access-rights your application requires and the roles that are assigned to users, translating between the two when loading the user information.
|
||||
|
||||
[[authz-legacy-note]]
|
||||
== Legacy Authorization Components
|
||||
|
||||
[NOTE]
|
||||
Spring Security contains some legacy components.
|
||||
Since they are not yet removed, documentation is included for historical purposes.
|
||||
Their recommended replacements are above.
|
||||
|
||||
[[authz-access-decision-manager]]
|
||||
=== The AccessDecisionManager
|
||||
|
@ -72,8 +266,6 @@ Whilst users can implement their own `AccessDecisionManager` to control all aspe
|
|||
.Voting Decision Manager
|
||||
image::{figures}/access-decision-voting.png[]
|
||||
|
||||
|
||||
|
||||
Using this approach, a series of `AccessDecisionVoter` implementations are polled on an authorization decision.
|
||||
The `AccessDecisionManager` then decides whether or not to throw an `AccessDeniedException` based on its assessment of the votes.
|
||||
|
||||
|
@ -104,7 +296,6 @@ Like the other implementations, there is a parameter that controls the behaviour
|
|||
It is possible to implement a custom `AccessDecisionManager` that tallies votes differently.
|
||||
For example, votes from a particular `AccessDecisionVoter` might receive additional weighting, whilst a deny vote from a particular voter may have a veto effect.
|
||||
|
||||
|
||||
[[authz-role-voter]]
|
||||
==== RoleVoter
|
||||
The most commonly used `AccessDecisionVoter` provided with Spring Security is the simple `RoleVoter`, which treats configuration attributes as simple role names and votes to grant access if the user has been assigned that role.
|
||||
|
@ -130,14 +321,6 @@ Obviously, you can also implement a custom `AccessDecisionVoter` and you can put
|
|||
It might be specific to your application (business-logic related) or it might implement some security administration logic.
|
||||
For example, you'll find a https://spring.io/blog/2009/01/03/spring-security-customization-part-2-adjusting-secured-session-in-real-time[blog article] on the Spring web site which describes how to use a voter to deny access in real-time to users whose accounts have been suspended.
|
||||
|
||||
|
||||
[[authz-after-invocation-handling]]
|
||||
== After Invocation Handling
|
||||
Whilst the `AccessDecisionManager` is called by the `AbstractSecurityInterceptor` before proceeding with the secure object invocation, some applications need a way of modifying the object actually returned by the secure object invocation.
|
||||
Whilst you could easily implement your own AOP concern to achieve this, Spring Security provides a convenient hook that has several concrete implementations that integrate with its ACL capabilities.
|
||||
|
||||
<<authz-after-invocation>> illustrates Spring Security's `AfterInvocationManager` and its concrete implementations.
|
||||
|
||||
[[authz-after-invocation]]
|
||||
.After Invocation Implementation
|
||||
image::{figures}/after-invocation.png[]
|
||||
|
@ -151,41 +334,3 @@ If you're using the typical Spring Security included `AccessDecisionManager` imp
|
|||
In turn, if the `AccessDecisionManager` property "`allowIfAllAbstainDecisions`" is `false`, an `AccessDeniedException` will be thrown.
|
||||
You may avoid this potential issue by either (i) setting "`allowIfAllAbstainDecisions`" to `true` (although this is generally not recommended) or (ii) simply ensure that there is at least one configuration attribute that an `AccessDecisionVoter` will vote to grant access for.
|
||||
This latter (recommended) approach is usually achieved through a `ROLE_USER` or `ROLE_AUTHENTICATED` configuration attribute.
|
||||
|
||||
|
||||
[[authz-hierarchical-roles]]
|
||||
== Hierarchical Roles
|
||||
It is a common requirement that a particular role in an application should automatically "include" other roles.
|
||||
For example, in an application which has the concept of an "admin" and a "user" role, you may want an admin to be able to do everything a normal user can.
|
||||
To achieve this, you can either make sure that all admin users are also assigned the "user" role.
|
||||
Alternatively, you can modify every access constraint which requires the "user" role to also include the "admin" role.
|
||||
This can get quite complicated if you have a lot of different roles in your application.
|
||||
|
||||
The use of a role-hierarchy allows you to configure which roles (or authorities) should include others.
|
||||
An extended version of Spring Security's <<authz-role-voter,RoleVoter>>, `RoleHierarchyVoter`, is configured with a `RoleHierarchy`, from which it obtains all the "reachable authorities" which the user is assigned.
|
||||
A typical configuration might look like this:
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
|
||||
<bean id="roleVoter" class="org.springframework.security.access.vote.RoleHierarchyVoter">
|
||||
<constructor-arg ref="roleHierarchy" />
|
||||
</bean>
|
||||
<bean id="roleHierarchy"
|
||||
class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
|
||||
<property name="hierarchy">
|
||||
<value>
|
||||
ROLE_ADMIN > ROLE_STAFF
|
||||
ROLE_STAFF > ROLE_USER
|
||||
ROLE_USER > ROLE_GUEST
|
||||
</value>
|
||||
</property>
|
||||
</bean>
|
||||
----
|
||||
|
||||
Here we have four roles in a hierarchy `ROLE_ADMIN => ROLE_STAFF => ROLE_USER => ROLE_GUEST`.
|
||||
A user who is authenticated with `ROLE_ADMIN`, will behave as if they have all four roles when security constraints are evaluated against an `AccessDecisionManager` configured with the above `RoleHierarchyVoter`.
|
||||
The `>` symbol can be thought of as meaning "includes".
|
||||
|
||||
Role hierarchies offer a convenient means of simplifying the access-control configuration data for your application and/or reducing the number of authorities which you need to assign to a user.
|
||||
For more complex requirements you may wish to define a logical mapping between the specific access-rights your application requires and the roles that are assigned to users, translating between the two when loading the user information.
|
||||
|
|
|
@ -0,0 +1,171 @@
|
|||
[[servlet-authorization-authorizationfilter]]
|
||||
= Authorize HttpServletRequests with AuthorizationFilter
|
||||
:figures: servlet/authorization
|
||||
|
||||
This section builds on xref:servlet/architecture.adoc#servlet-architecture[Servlet Architecture and Implementation] by digging deeper into how xref:servlet/authorization/index.adoc#servlet-authorization[authorization] works within Servlet-based applications.
|
||||
|
||||
[NOTE]
|
||||
`AuthorizationFilter` supersedes xref:servlet/authorization/authorize-requests.adoc#servlet-authorization-filtersecurityinterceptor[`FilterSecurityInterceptor`].
|
||||
To remain backward compatible, `FilterSecurityInterceptor` remains the default.
|
||||
This section discusses how `AuthorizationFilter` works and how to override the default configuration.
|
||||
|
||||
The {security-api-url}org/springframework/security/web/access/intercept/AuthorizationFilter.html[`AuthorizationFilter`] provides xref:servlet/authorization/index.adoc#servlet-authorization[authorization] for ``HttpServletRequest``s.
|
||||
It is inserted into the xref:servlet/architecture.adoc#servlet-filterchainproxy[FilterChainProxy] as one of the xref:servlet/architecture.adoc#servlet-security-filters[Security Filters].
|
||||
|
||||
You can override the default when you declare a `SecurityFilterChain`.
|
||||
Instead of using xref:servlet/authorization/authorize-http-requests.adoc#servlet-authorize-requests-defaults[`authorizeRequests`], use `authorizeHttpRequests`, like so:
|
||||
|
||||
.Use authorizeHttpRequests
|
||||
====
|
||||
.Java
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@Bean
|
||||
SecurityFilterChain web(HttpSecurity http) throws AuthenticationException {
|
||||
http
|
||||
.authorizeHttpRequests((authorize) -> authorize
|
||||
.anyRequest().authenticated();
|
||||
)
|
||||
// ...
|
||||
|
||||
return http.build();
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
This improves on `authorizeRequests` in a number of ways:
|
||||
|
||||
1. Uses the simplified `AuthorizationManager` API instead of metadata sources, config attributes, decision managers, and voters.
|
||||
This simplifies reuse and customization.
|
||||
2. Delays `Authentication` lookup.
|
||||
Instead of the authentication needing to be looked up for every request, it will only look it up in requests where an authorization decision requires authentication.
|
||||
3. Bean-based configuration support.
|
||||
|
||||
When `authorizeHttpRequests` is used instead of `authorizeRequests`, then {security-api-url}org/springframework/security/web/access/intercept/AuthorizationFilter.html[`AuthorizationFilter`] is used instead of xref:servlet/authorization/authorize-requests.adoc#servlet-authorization-filtersecurityinterceptor[`FilterSecurityInterceptor`].
|
||||
|
||||
.Authorize HttpServletRequest
|
||||
image::{figures}/authorizationfilter.png[]
|
||||
|
||||
* image:{icondir}/number_1.png[] First, the `AuthorizationFilter` obtains an xref:servlet/authentication/architecture.adoc#servlet-authentication-authentication[Authentication] from the xref:servlet/authentication/architecture.adoc#servlet-authentication-securitycontextholder[SecurityContextHolder].
|
||||
It wraps this in an `Supplier` in order to delay lookup.
|
||||
* image:{icondir}/number_2.png[] Second, `AuthorizationFilter` creates a {security-api-url}org/springframework/security/web/FilterInvocation.html[`FilterInvocation`] from the `HttpServletRequest`, `HttpServletResponse`, and `FilterChain`.
|
||||
// FIXME: link to FilterInvocation
|
||||
* image:{icondir}/number_3.png[] Next, it passes the `Supplier<Authentication>` and `FilterInvocation` to the xref:servlet/architecture.adoc#authz-authorization-manager[`AuthorizationManager`].
|
||||
** image:{icondir}/number_4.png[] If authorization is denied, an `AccessDeniedException` is thrown.
|
||||
In this case the xref:servlet/architecture.adoc#servlet-exceptiontranslationfilter[`ExceptionTranslationFilter`] handles the `AccessDeniedException`.
|
||||
** image:{icondir}/number_5.png[] If access is granted, `AuthorizationFilter` continues with the xref:servlet/architecture.adoc#servlet-filters-review[FilterChain] which allows the application to process normally.
|
||||
|
||||
We can configure Spring Security to have different rules by adding more rules in order of precedence.
|
||||
|
||||
.Authorize Requests
|
||||
====
|
||||
.Java
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@Bean
|
||||
SecurityFilterChain web(HttpSecurity http) throws Exception {
|
||||
http
|
||||
// ...
|
||||
.authorizeHttpRequests(authorize -> authorize // <1>
|
||||
.mvcMatchers("/resources/**", "/signup", "/about").permitAll() // <2>
|
||||
.mvcMatchers("/admin/**").hasRole("ADMIN") // <3>
|
||||
.mvcMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')") // <4>
|
||||
.anyRequest().denyAll() // <5>
|
||||
);
|
||||
|
||||
return http.build();
|
||||
}
|
||||
----
|
||||
====
|
||||
<1> There are multiple authorization rules specified.
|
||||
Each rule is considered in the order they were declared.
|
||||
<2> We specified multiple URL patterns that any user can access.
|
||||
Specifically, any user can access a request if the URL starts with "/resources/", equals "/signup", or equals "/about".
|
||||
<3> Any URL that starts with "/admin/" will be restricted to users who have the role "ROLE_ADMIN".
|
||||
You will notice that since we are invoking the `hasRole` method we do not need to specify the "ROLE_" prefix.
|
||||
<4> Any URL that starts with "/db/" requires the user to have both "ROLE_ADMIN" and "ROLE_DBA".
|
||||
You will notice that since we are using the `hasRole` expression we do not need to specify the "ROLE_" prefix.
|
||||
<5> Any URL that has not already been matched on is denied access.
|
||||
This is a good strategy if you do not want to accidentally forget to update your authorization rules.
|
||||
|
||||
You can take a bean-based approach by constructing your own xref:servlet/authorization/architecture.adoc#authz-delegate-authorization-manager[`RequestMatcherDelegatingAuthorizationManager`] like so:
|
||||
|
||||
.Configure RequestMatcherDelegatingAuthorizationManager
|
||||
====
|
||||
.Java
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@Bean
|
||||
SecurityFilterChain web(HttpSecurity http, AuthorizationManager<RequestAuthorizationContext> access)
|
||||
throws AuthenticationException {
|
||||
http
|
||||
.authorizeHttpRequests((authorize) -> authorize
|
||||
.anyRequest().access(access)
|
||||
)
|
||||
// ...
|
||||
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
AuthorizationManager<RequestAuthorizationContext> requestMatcherAuthorizationManager(HandlerMappingIntrospector introspector) {
|
||||
RequestMatcher permitAll =
|
||||
new AndRequestMatcher(
|
||||
new MvcRequestMatcher(introspector, "/resources/**"),
|
||||
new MvcRequestMatcher(introspector, "/signup"),
|
||||
new MvcRequestMatcher(introspector, "/about"));
|
||||
RequestMatcher admin = new MvcRequestMatcher(introspector, "/admin/**");
|
||||
RequestMatcher db = new MvcRequestMatcher(introspector, "/db/**");
|
||||
RequestMatcher any = AnyRequestMatcher.INSTANCE;
|
||||
AuthorizationManager<HttpRequestServlet> manager = RequestMatcherDelegatingAuthorizationManager.builder()
|
||||
.add(permitAll, (context) -> new AuthorizationDecision(true))
|
||||
.add(admin, AuthorityAuthorizationManager.hasRole("ADMIN"))
|
||||
.add(db, AuthorityAuthorizationManager.hasRole("DBA"))
|
||||
.add(any, new AuthenticatedAuthorizationManager())
|
||||
.build();
|
||||
return (context) -> manager.check(context.getRequest());
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
You can also wire xref:servlet/authorization/architecture.adoc#authz-custom-authorization-manager[your own custom authorization managers] for any request matcher.
|
||||
|
||||
Here is an example of mapping a custom authorization manager to the `my/authorized/endpoint`:
|
||||
|
||||
.Custom Authorization Manager
|
||||
====
|
||||
.Java
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@Bean
|
||||
SecurityFilterChain web(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeHttpRequests((authorize) -> authorize
|
||||
.mvcMatchers("/my/authorized/endpoint").access(new CustomAuthorizationManager());
|
||||
)
|
||||
// ...
|
||||
|
||||
return http.build();
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
Or you can provide it for all requests as seen below:
|
||||
|
||||
.Custom Authorization Manager for All Requests
|
||||
====
|
||||
.Java
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@Bean
|
||||
SecurityFilterChain web(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeHttpRequests((authorize) -> authorize
|
||||
.anyRequest.access(new CustomAuthorizationManager());
|
||||
)
|
||||
// ...
|
||||
|
||||
return http.build();
|
||||
}
|
||||
----
|
||||
====
|
|
@ -2,6 +2,10 @@
|
|||
= Authorize HttpServletRequest with FilterSecurityInterceptor
|
||||
:figures: servlet/authorization
|
||||
|
||||
[NOTE]
|
||||
`FilterSecurityInterceptor` is in the process of being replaced by xref:servlet/authorization/authorize-http-requests.adoc[`AuthorizationFilter`].
|
||||
Consider using that instead.
|
||||
|
||||
This section builds on xref:servlet/architecture.adoc#servlet-architecture[Servlet Architecture and Implementation] by digging deeper into how xref:servlet/authorization/index.adoc#servlet-authorization[authorization] works within Servlet based applications.
|
||||
|
||||
The {security-api-url}org/springframework/security/web/access/intercept/FilterSecurityInterceptor.html[`FilterSecurityInterceptor`] provides xref:servlet/authorization/index.adoc#servlet-authorization[authorization] for ``HttpServletRequest``s.
|
||||
|
@ -14,7 +18,7 @@ image::{figures}/filtersecurityinterceptor.png[]
|
|||
* image:{icondir}/number_2.png[] Second, `FilterSecurityInterceptor` creates a {security-api-url}org/springframework/security/web/FilterInvocation.html[`FilterInvocation`] from the `HttpServletRequest`, `HttpServletResponse`, and `FilterChain` that are passed into the `FilterSecurityInterceptor`.
|
||||
// FIXME: link to FilterInvocation
|
||||
* image:{icondir}/number_3.png[] Next, it passes the `FilterInvocation` to `SecurityMetadataSource` to get the ``ConfigAttribute``s.
|
||||
* image:{icondir}/number_4.png[] Finally, it passes the `Authentication`, `FilterInvocation`, and ``ConfigAttribute``s to the `AccessDecisionManager`.
|
||||
* image:{icondir}/number_4.png[] Finally, it passes the `Authentication`, `FilterInvocation`, and ``ConfigAttribute``s to the xref:servlet/authorization.adoc#authz-access-decision-manager`AccessDecisionManager`.
|
||||
** image:{icondir}/number_5.png[] If authorization is denied, an `AccessDeniedException` is thrown.
|
||||
In this case the xref:servlet/architecture.adoc#servlet-exceptiontranslationfilter[`ExceptionTranslationFilter`] handles the `AccessDeniedException`.
|
||||
** image:{icondir}/number_6.png[] If access is granted, `FilterSecurityInterceptor` continues with the xref:servlet/architecture.adoc#servlet-filters-review[FilterChain] which allows the application to process normally.
|
||||
|
@ -24,6 +28,7 @@ In this case the xref:servlet/architecture.adoc#servlet-exceptiontranslationfilt
|
|||
By default, Spring Security's authorization will require all requests to be authenticated.
|
||||
The explicit configuration looks like:
|
||||
|
||||
[[servlet-authorize-requests-defaults]]
|
||||
.Every Request Must be Authenticated
|
||||
====
|
||||
.Java
|
||||
|
@ -32,7 +37,7 @@ The explicit configuration looks like:
|
|||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
// ...
|
||||
.authorizeHttpRequests(authorize -> authorize
|
||||
.authorizeRequests(authorize -> authorize
|
||||
.anyRequest().authenticated()
|
||||
);
|
||||
}
|
||||
|
@ -71,7 +76,7 @@ We can configure Spring Security to have different rules by adding more rules in
|
|||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
// ...
|
||||
.authorizeHttpRequests(authorize -> authorize // <1>
|
||||
.authorizeRequests(authorize -> authorize // <1>
|
||||
.mvcMatchers("/resources/**", "/signup", "/about").permitAll() // <2>
|
||||
.mvcMatchers("/admin/**").hasRole("ADMIN") // <3>
|
||||
.mvcMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')") // <4>
|
||||
|
|
Loading…
Reference in New Issue