This is the seventh day of my participation in the First Challenge 2022. For details: First Challenge 2022.
# Springboot integration shiro — front and back end separation mode (part 1)
During the integration of Shiro, I also encountered a lot of problems, mainly login authentication. When authentication is well done, there are basically no problems with authorization. I also hit a break point and followed the process for more than ten times to almost clear the whole authentication process.
First of all, I will start with the official login flow chart. I have looked at the official document and summarized as follows:
- The application code calls the subject.login method and passes in a constructed AuthenticationToken instance representing the end user principal and credentials.
- The Subject instance, usually the DelegatingSubject (or subclass) delegates to the application’s SecurityManager by calling SecurityManager.login (token), where the actual authentication begins.
- SecurityManager as a basic component “umbrella”, receives the token and by calling the Authenticator, authenticate (token) simply entrusted to its internal Authenticator instance. Are basically ModularRealmAuthenticator instance, it supports during authentication coordination of one or more examples of Realm. Modularrealmauthentator essentially provides a PAM-style paradigm for Apache Shiro (in PAM terminology, each realm is a “module”).
- If the application is configured with multiple realm, ModularRealmAuthenticator instance will use its configuration AuthenticationStrategy start multidisciplinary authentication attempt. Before, during, and after the authentication of the calling realm, the AuthenticationStrategy is called to allow it to react to the results of each realm.
- Check to see if each configured Realm supports the submitted AuthenticationToken. The realm-enabled getawatitationInfo method will be called by the submitted token. The getAuthenticationInfo method effectively represents a single authentication attempt for a particular realm.
Then look at the flow chart of my program:
Because of the separation of the front and back ends, I rewrote the Filter for Shiro certification, so my certification starts with the filter and normally ends with the executeLogin(Request, Response) method, which is the starting point for our certification.
If you click on this method, you can see that the first step is to create the token. In the previous article, I mentioned that I have rewritten this method, because it is related to the authentication in realm later, so we have to decide what kind of token to create and how to authenticate in realm.
The createToken method I rewrote is the token object that I need to put in the createToken method. The authentication is determined by the token value in the realm.
@Override protected AuthenticationToken createToken(ServletRequest request, ServletResponse Response) throws Exception {// Obtain the request Token (dataId) String Token = TokenUtil.getRequestToken((HttpServletRequest) request); return new AuthToken(token); }Copy the code
After our token object is created, we go to the subjective.login (token) method, and we follow up with the securityManager securityManager and then call securitymanager.login (this, token).
Inside this method is to get our AuthenticationInfo object, the authentication information object, which is actually the object returned by our custom UserRealm override authentication method
We then enter authenticate(token) and see that info is returned by doAuthenticate(token)
We will first determine the number of realms we have configured and then decide which logic to use. We will use the single realm method with only one realm. Multiple realms should be more complicated
Then came to doSingleRealmAuthentication method, here is according to our custom realm to obtain the Info
The first step is to get the info from Shiro’s cache and determine if it is empty
So let’s see if it’s empty then we go to doGetAuthenticationInfo(Token) method, and that’s the method that we’re overwriting in UserRealm, and we’re just going to authenticate it and return info, so that’s the result of the first call, When the first request is blocked by the filter and we go all the way here, assuming we’ve called the login interface and got the token value. Because I’m not going to pass through the filter for the login, so I’m going to log in and get the token for the identity information, and then the other requests the first time they take the token for the identity information all the way up here and when they pass through our authentication logic they’re going to generate an info object, The info object’s second argument, the token value representing the identity information, is returned and stored in Shiro’s cache
And then we’re going to look at the info not being empty, so this is not the first time, we’ve authenticated our info in the cache, and then we’re going to call assertCredentialsMatch, This method will first get something like a matcher to verify that the token passed in matches the info in the cache, and we will continue to click on it
There are many different implementations, but the last one is used here, which is to compare info and token. Hit a break point and run away
If you don’t want to use a token, you can change it to a user name for password verification. When you create a token, you put the password in it. When you generate info, you put the password in it
At this point, the logic of user authentication is over. After authentication, there is generally no problem with authorization, which is to find permissions and roles from the database and then set them to the user. Here I use annotated permission check, and write a annotation on the interface to do permission restrictions.