Open lihongjie0209 opened 3 years ago
AccessDecisionVoter 接口返回 弃权, 同意, 拒绝 三种状态
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.
The AccessDecisionVoter
interface has three methods:
int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attrs);
boolean supports(ConfigAttribute attribute);
boolean supports(Class clazz);
Concrete implementations return an int
, with possible values being reflected in the AccessDecisionVoter
static fields ACCESS_ABSTAIN
, ACCESS_DENIED
and ACCESS_GRANTED
.
A voting implementation will return ACCESS_ABSTAIN
if it has no opinion on an authorization decision.
If it does have an opinion, it must return either ACCESS_DENIED
or ACCESS_GRANTED
.
There are three concrete AccessDecisionManager
s provided with Spring Security that tally the votes.
The ConsensusBased
implementation will grant or deny access based on the consensus of non-abstain votes.
Properties are provided to control behavior in the event of an equality of votes or if all votes are abstain.
The AffirmativeBased
implementation will grant access if one or more ACCESS_GRANTED
votes were received (i.e. a deny vote will be ignored, provided there was at least one grant vote).
Like the ConsensusBased
implementation, there is a parameter that controls the behavior if all voters abstain.
The UnanimousBased
provider expects unanimous ACCESS_GRANTED
votes in order to grant access, ignoring abstains.
It will deny access if there is any ACCESS_DENIED
vote.
Like the other implementations, there is a parameter that controls the behaviour if all voters abstain.
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.
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.
It will vote if any ConfigAttribute
begins with the prefix ROLE_
.
It will vote to grant access if there is a GrantedAuthority
which returns a String
representation (via the getAuthority()
method) exactly equal to one or more ConfigAttributes
starting with the prefix ROLE_
.
If there is no exact match of any ConfigAttribute
starting with ROLE_
, the RoleVoter
will vote to deny access.
If no ConfigAttribute
begins with ROLE_
, the voter will abstain.
Another voter which we’ve implicitly seen is the AuthenticatedVoter
, which 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.
When we’ve used the attribute IS_AUTHENTICATED_ANONYMOUSLY
to grant anonymous access, this attribute was being processed by the AuthenticatedVoter
.
See the Javadoc for this class for more information.
Obviously, you can also implement a custom AccessDecisionVoter
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’ll find a 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.
AccessDecisionVoter 接口返回 弃权, 同意, 拒绝 三种状态
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.
The AccessDecisionVoter
interface has three methods:
int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attrs);
boolean supports(ConfigAttribute attribute);
boolean supports(Class clazz);
Concrete implementations return an int
, with possible values being reflected in the AccessDecisionVoter
static fields ACCESS_ABSTAIN
, ACCESS_DENIED
and ACCESS_GRANTED
.
A voting implementation will return ACCESS_ABSTAIN
if it has no opinion on an authorization decision.
If it does have an opinion, it must return either ACCESS_DENIED
or ACCESS_GRANTED
.
There are three concrete AccessDecisionManager
s provided with Spring Security that tally the votes.
The ConsensusBased
implementation will grant or deny access based on the consensus of non-abstain votes.
Properties are provided to control behavior in the event of an equality of votes or if all votes are abstain.
The AffirmativeBased
implementation will grant access if one or more ACCESS_GRANTED
votes were received (i.e. a deny vote will be ignored, provided there was at least one grant vote).
Like the ConsensusBased
implementation, there is a parameter that controls the behavior if all voters abstain.
The UnanimousBased
provider expects unanimous ACCESS_GRANTED
votes in order to grant access, ignoring abstains.
It will deny access if there is any ACCESS_DENIED
vote.
Like the other implementations, there is a parameter that controls the behaviour if all voters abstain.
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.
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.
It will vote if any ConfigAttribute
begins with the prefix ROLE_
.
It will vote to grant access if there is a GrantedAuthority
which returns a String
representation (via the getAuthority()
method) exactly equal to one or more ConfigAttributes
starting with the prefix ROLE_
.
If there is no exact match of any ConfigAttribute
starting with ROLE_
, the RoleVoter
will vote to deny access.
If no ConfigAttribute
begins with ROLE_
, the voter will abstain.
Another voter which we’ve implicitly seen is the AuthenticatedVoter
, which 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.
When we’ve used the attribute IS_AUTHENTICATED_ANONYMOUSLY
to grant anonymous access, this attribute was being processed by the AuthenticatedVoter
.
See the Javadoc for this class for more information.
Obviously, you can also implement a custom AccessDecisionVoter
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’ll find a 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.
同步AccessDecisionManager调用多个voter, 然后综合结果来决定是否可以访问, 如果拒绝访问那么抛出异常
The AccessDecisionManager
is called by the AbstractSecurityInterceptor
and is responsible for making final access control decisions.
The AccessDecisionManager
interface contains three methods:
void decide(Authentication authentication, Object secureObject,
Collection<ConfigAttribute> attrs) throws AccessDeniedException;
boolean supports(ConfigAttribute attribute);
boolean supports(Class clazz);
The AccessDecisionManager
's decide
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 AccessDecisionManager
to ensure the principal is permitted to operate on that customer.
Implementations are expected to throw an AccessDeniedException
if access is denied.
The supports(ConfigAttribute)
method is called by the AbstractSecurityInterceptor
at startup time to determine if the AccessDecisionManager
can process the passed ConfigAttribute
.
The supports(Class)
method is called by a security interceptor implementation to ensure the configured AccessDecisionManager
supports the type of secure object that the security interceptor will present.
protected void configure(HttpSecurity http) throws Exception {
http
// ...
.authorizeRequests(authorize -> authorize
.mvcMatchers("/resources/**", "/signup", "/about").permitAll()
.mvcMatchers("/admin/**").hasRole("ADMIN")
.mvcMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")
.anyRequest().denyAll()
);
}
if (SecurityContextHolder.getContext().getAuthentication() == null) {
credentialsNotFound(messages.getMessage(
"AbstractSecurityInterceptor.authenticationNotFound",
"An Authentication object was not found in the SecurityContext"),
object, attributes);
}
Authentication authenticated = authenticateIfRequired();
// Attempt authorization
try {
this.accessDecisionManager.decide(authenticated, object, attributes);
}
catch (AccessDeniedException accessDeniedException) {
publishEvent(new AuthorizationFailureEvent(object, attributes, authenticated,
accessDeniedException));
throw accessDeniedException;
}
The most obviously useful annotation is @PreAuthorize
which decides whether a method can actually be invoked or not.
For example (from the "Contacts" sample application)
@PreAuthorize("hasRole('USER')")
public void create(Contact contact);
which means that access will only be allowed for users with the role "ROLE_USER". Obviously the same thing could easily be achieved using a traditional configuration and a simple configuration attribute for the required role. But what about:
@PreAuthorize("hasPermission(#contact, 'admin')")
public void deletePermission(Contact contact, Sid recipient, Permission permission);
Here we’re actually using a method argument as part of the expression to decide whether the current user has the "admin"permission for the given contact.
The built-in hasPermission()
expression is linked into the Spring Security ACL module through the application context, as we’ll see below.
You can access any of the method arguments by name as expression variables.
There are a number of ways in which Spring Security can resolve the method arguments.
Spring Security uses DefaultSecurityParameterNameDiscoverer
to discover the parameter names.
By default, the following options are tried for a method as a whole.
如何存储授权信息
简单来说就是一个String
Authentication
, discusses how allAuthentication
implementations store a list ofGrantedAuthority
objects. These represent the authorities that have been granted to the principal. theGrantedAuthority
objects are inserted into theAuthentication
object by theAuthenticationManager
and are later read byAccessDecisionManager
s when making authorization decisions.GrantedAuthority
is an interface with only one method:This method allows
AccessDecisionManager
s to obtain a preciseString
representation of theGrantedAuthority
. By returning a representation as aString
, aGrantedAuthority
can be easily "read" by mostAccessDecisionManager
s. If aGrantedAuthority
cannot be precisely represented as aString
, theGrantedAuthority
is considered "complex" andgetAuthority()
must returnnull
.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 complexGrantedAuthority
as aString
would be quite difficult, and as a result thegetAuthority()
method should returnnull
. This will indicate to anyAccessDecisionManager
that it will need to specifically support theGrantedAuthority
implementation in order to understand its contents.