Prior to spring security
I used to Interceptor
implement a simple website demo of the login interception and session processing work, although the ability to achieve the corresponding functions, but no doubt spring security provides a more simple configuration method to better protect the Web application.
Related structures of Spring security
Here you can refer to spring Security's official introduction document: Spring-security-architecture
In simple terms:
- Spring security is a single
Filter
, and its specific type is FilterChainProxy
that it is configured as @Bean
in ApplicationContext
.
From the container's point of view, Spring security is a single filter, but there are a lot of extra filter, each of which plays their respective roles, as shown in:
Spring Security's authentication, which is mainly AuthenticationManager
done by this interface, is the main method of verifyingauthenticate()
public interface AuthenticationManager { Authentication authenticate(Authentication authentication) throws AuthenticationException; }
- This method can accomplish three things:
- If it can verify that the input represents a valid principal, it returns one
Authentication
(usually included authenticated=true
)
- If it can verify that the input represents an invalid principal, throw a
AuthenticationException
- If it can't decide, it's back.
null
- The most common
AuthicationManager
implementation is ProviderManager
that it delegates it to AuthticationProvider
this instance, AuthenticationProvider
and AuthenticationManager
a little bit like it, but contains some extra methods to allow the caller to query whether the form is supported Authenticaion
.
public interface AuthenticationProvider { Authentication authenticate(Authentication authentication) throws AuthenticationException; boolean supports(Class<?> authentication); }
supports()
The argument in the method Class<?>
is Class<? extends Authentication>
that it only asks if it supports passing to the authenticate()
method.
- In the same program, one can
ProviderManager
support several different authentication mechanisms by delegating a series of them, and AuthenticaitonProviders
if ProviderManager
a particular instance type is not recognized Authentication
, it is skipped.
Many times, a program contains multiple resource protection logical groups, each with their own unique AuthenticationManager
, usually they share the parent, then the parent becomes one "global"资源
, as all provider
the backs.
Spring Security offers a number of configurations that help us quickly turn on validation, and most commonly AuthenticationManagerBuiler
, it's good at memory (in-memory), JDBC, LDAP, or personal customization UserDetailService
.
Using spring security for access and permission control
Note: This follow-up code is implemented with Springboot as the framework, and its Demo Git:spring-security-demo
- Access and privilege control mainly through the Configure method of overloading Websecurityconfigureradapter
Method |
Description |
Configure (Websecurity) |
Configure spring Security's filter chain by overloading |
Configure (Httpsecurity) |
Configuring how interceptor protection requests are through overloading |
Configure (Authenticationmanagerbuilder) |
Configuring the User-detail service with overloading |
- We rewrite the following methods:
@Override protected void Configure (Httpsecurity http) throws Exception {http. authorizerequests () . Antmatchers ("/index"). Hasanyauthority ("Role_user", "Role_admin"). Antmatchers ("/oss"). Hasauthority ("ROLE_ADMIN "). Antmatchers (Httpmethod.get,"/login "). Permitall (). Anyrequest (). authenticated (). and (). fo Rmlogin (). LoginPage ("/login"). Permitall ()//.successhandler (Successhandler). and (). Logout () . Logoutsuccessurl ("/"). Permitall (); } @Override protected void Configure (Authenticationmanagerbuilder auth) throws Exception {Auth.inmemorya Uthentication (). Passwordencoder (New Bcryptpasswordencoder ()). Withuser ("root"). Password (new Bcryptpassworde Ncoder (). Encode ("root")). Roles ("USER", "ADMIN"). and (). Withuser ("normal"). Password (new Bcryptpasswordencoder (). Encode ("normal")). Roles ("USER"); Auth.authenticationprovider (Userprovider); Auth.authenticationprovider (Afterprovider); }
-url matching via ' antmatchers () ', then corresponding processing, such as the code, we intercepted the **/index** and **/oss** two links, respectively, required to have ' role_user ' or ' Role_ ADMIN ', ' role_admin ' to access the two identities. -' Anyrequest (). Authenticated () ' means that other requests will need to be verified-' formlogin () ' To have the login page, and if there is no subsequent ' loginpage () ', a spring will be generated by default Security page, and the later commented out ' Successhandler ' is the next. -' Permitall () ' indicates that the current connection does not require authentication. -' logout () ' Will intercept the **\logout** request, complete the logout operation, ' Logoutsuccessurl () ' is the redirected address after logout. -' and () ' in which the connection works.
- Some common ways to configure protection paths
- Authenticated (): Allow authenticated user access
- Denyall (): Unconditional denial of all access
- Fullyauthenticated (): If the user is fully authenticated (not through remeber me) access
- Hasipadress (String): If you are riding a cow from a given IP address, you can access
- Hasanyauthority (String ...): If used with any given role, you can access
- Hasanthority (String): If the user has a given role, they can access
- Permital (): unconditional Allow method
- Remeberme (): If the user is authenticated by Remeber-me, they can access
- In addition, with autheority to have a ROLE, both is a concept, autheority must start with "Role_", and ROLE does not need, see the code.
At this point, our root account can access both the index and the OSS, and the normal account can only access index, cannot access the OSS, if access to OSS will appear:
There is an unexpected error (Type=forbidden, status=403).
Above we have generated two memory user root and normal by overloading configure (Authenticationmanagerbuilder auth), and we can do so through JDBC.
Processing after successful certification through Authenticationsuccesshandler
- By implementing the Authenticationsuccesshandler interface, we can execute the corresponding code after the validation is successful, such as
Token
settings and so on, such as I now print a login information and redirect the request to the first page
@Componentpublic class SuccessHandler implements AuthenticationSuccessHandler{ @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { System.out.println(authentication.getName()+" is loging , role is"+authentication.getAuthorities()); response.sendRedirect("/"); }
- and add it to the
formLogin()
post, namely:
.formLogin() .loginPage("/login") .permitAll().successHandler(successHandler)
- Log in to the root account again, and you'll see it on the console: root is loging, role is[role_admin, Role_user]
Personalized authentication via Authenticationprovider
- We create a
userauthprovider
and let it implement the Authenticationprovider
interface:
@Override Public authentication Authenticate (authentication authentication) throws Authenticationexception { System.out.println ("-----------------------------------------------------------------------"); System.out.println ("This is Userauthprovider"); SYSTEM.OUT.PRINTLN ("Starting authenticate ..."); System.out.println ("Credentials:" +authentication.getcredentials ()); System.out.println ("Name:" +authentication.getname ()); System.out.println ("Class:" +authentication.getclass ()); System.out.println ("Details:" +authentication.getdetails ()); System.out.println ("Principal:" +authentication.getprincipal ()); System.out.println ("-----------------------------------------------------------------------"); Usernamepasswordauthenticationtoken auth=new Usernamepasswordauthenticationtoken (Authentication.getPrincipal (), Authentication.getcredentials ()); return auth; } @Override Public Boolean supportS (class<?> authentication) {SYSTEM.OUT.PRINTLN ("This is Userauthprovider"); SYSTEM.OUT.PRINTLN ("starting supports"); System.out.println (Authentication.getclass ()); return false; }
- At the same time, we comment out the previous
auth.inMemoryAuthentication()
, add Userauthprovider to the AuthenticationManagerBuilder
, namely:
@Override protected void configure(AuthenticationManagerBuilder auth) throws Exception {// auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())// .withUser("root").password(new BCryptPasswordEncoder().encode("root")).roles("USER","ADMIN").and()// .withUser("normal").password(new BCryptPasswordEncoder().encode("normal")).roles("USER"); auth.authenticationProvider(userProvider); auth.authenticationProvider(afterProvider); }
- When we log in again, we will see that the console will output
This is UserAuthProvider starting supports java.lang.
- The reason is that we override the
supports()
method, always return False, and return false, that is no longer called authenticate()
for the authentication operation (as described above), we will supports()
return the value of True, login again (username:root password : 1234), the console will output
This is UserAuthProviderstarting supportsclass java.lang.Class-----------------------------------------------------------------------This is UserAuthProviderstarting authenticate ... ...Credentials:1234Name:rootClass:class org.springframework.security.authentication.UsernamePasswordAuthenticationTokenDetails:org.sprin[email protected]166c8: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: node04v47liue6knt1oghnzgiqb9dx0Principal:root-----------------------------------------------------------------------root is loging , role is[]
-
was successfully logged in because we declared an instance of authentication directly in the authenticate ()
method Usernamepasswordauthenticationtoken
, and returns, as stated above, when the authentication
instance is returned, the default is authorization succeeds, and if we return null
, the description cannot be determined and the login is not successful.
-
At this point we create an object Userafterprovider
, which also implements the Authenticationprovider
interface, and will The Userafterprovider
and userauthprovider
authenticate ()
return values are set to null
. We use the above data again to log in, the console output is as follows:
This is userauthproviderstarting Supportsclass Java.lang.Class-----------------------------------------------------------------------This is Userauthproviderstarting Authenticate ... Credentials:1234name:rootclass:class org.springframework.security.authentication.usernamepasswordauthenticationtokendetails:org.sprin[email Protected]43458:remoteipaddress:0:0:0:0:0:0:0:1; Sessionid:node01m47f3t6xq5a470fu07jaipzb0principal: Root-----------------------------------------------------------------------This is userafterproviderstarting Supportsclass Java.lang.Class-----------------------------------------------------------------------This is Userafterproviderstarting Authenticate ... Credentials:1234name:rootclass:class org.springframework.security.authentication.usernamepasswordauthenticationtokendetails:org.sprin[email Protected]43458:remoteipaddress:0:0:0:0:0:0:0:1; SessionId:node01m47f3t6xq5a470fu07jaipzb0Principal:root-----------------------------------------------------------------------
- , which is two porvider verified, did not pass (return null), stating that all validations that join
Authenticationmanagerbuilder
are performed once, So if we restore one of the provider authenticate ()
return values to the authentication
instance and log in again, the console will output the following result:
This is userauthproviderstarting Supportsclass Java.lang.Class-----------------------------------------------------------------------This is Userauthproviderstarting Authenticate ... Credentials:1234name:rootclass:class org.springframework.security.authentication.usernamepasswordauthenticationtokendetails:org.sprin[email Protected]166c8:remoteipaddress:0:0:0:0:0:0:0:1; Sessionid:node04v47liue6knt1oghnzgiqb9dx0principal: Root-----------------------------------------------------------------------root is loging, role Is[]this is Userauthproviderstarting Supportsclass Java.lang.Class-----------------------------------------------------------------------This is Userauthproviderstarting Authenticate ... Credentials:nullName:rootClass:class org.springframework.security.authentication.usernamepasswordauthenticationtokendetails:org.sprin[email Protected]166c8:remoteipaddress:0:0:0:0:0:0:0:1; SessionId:node04v47liue6knt1oghnzgiqb9dx0Principal:root-----------------------------------------------------------------------
Because we rewrote it AuthenticationSuccessHandler
, so verify that the success of the regret redirect to /, and my controller in the / another redirect to /index, so there was two verification, and this time we found that because UserAuthProvider
Passed, so there is UserAfterProvider
no validation, so we can know that as long as there is a provider passed the validation we can think passed the validation.
Therefore, we can AuthenticationProvider
write some of our own authentication logic through implementation, and even @autowire the related service to assist the implementation.
Spring Security Quick View