Shiro’s internal process for verifying username and password

Project code comes from:

12-Shiro and Springboot integration_bilibili_bilibili

Follow the Shang Silicon Valley WeChat public account and enter the shiro system to return the download link (the Baidu network disk link contains code and handouts):

The database table creation statement is in the handout, and you need to add test user data yourself.

The project is only suitable for learning testing, set two breakpoints:

1. Subject.login(token) around line 44 in ../controller/MyController.java;

/* com/atguigu/shiro/controller/MyController.java file */

@Controller
@RequestMapping("myController")
public class MyController {



    @GetMapping("userLogin")
    @ResponseBody
    public String userLogin(String name, String pwd,
                            @RequestParam(defaultValue = "false")boolean rememberMe,
                            HttpSession session){

        try {
            subject.login(token); //Breakpoint 1
            //return "Login successful";
            session.setAttribute("user",token.getPrincipal().toString());
            return "main";

        } catch (AuthenticationException e) {
            e.printStackTrace();
            System.out.println("Login failed");
            return "Login failed";
        }

    }

2. In the doGetAuthenticationInfo() method after line 46 in ../realm/MyRealm.java

/* In the doGetAuthenticationInfo() method in com/atguigu/shiro/realm/MyRealm.java*/

@Component
public class MyRealm extends AuthorizingRealm {


    //Customize login authentication method
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //1 Get user identity information
        String name = authenticationToken.getPrincipal().toString(); //Breakpoint 2
        //2 Call the business layer to obtain user information (database)
        User user = userService.getUserInfoByName(name);
        //3 Non-empty judgment, encapsulate the data and return it
        if(user !=null){
            AuthenticationInfo info = new SimpleAuthenticationInfo(
                    authenticationToken.getPrincipal(),
                    user.getPwd(),
                    ByteSource.Util.bytes("salt"),
                    authenticationToken.getPrincipal().toString()
            );
            return info;
        }
        return null;
    }
}

debug operation, call the interface http://localhost:8080/myController/userLogin?name=Zhang Shan &pwd=123456

The program running process goes through:

1. com.atguigu.shiro.controller.MyController#userLogin(java.lang.String, java.lang.String, boolean, javax.servlet.http.HttpSession), carrying parameter token

2. org.apache.shiro.subject.support.DelegatingSubject#login, carrying parameter token

3. org.apache.shiro.mgt.DefaultSecurityManager#login, carrying parameter token

4. org.apache.shiro.mgt.AuthenticatingSecurityManager#authenticate, carrying parameter token

5. org.apache.shiro.authc.AbstractAuthenticator#authenticate, carrying parameter token

6. org.apache.shiro.authc.pam.ModularRealmAuthenticator#doAuthenticate, there are two parameters passed to the next level, namely Realm object and authenticationToken.

The Realm object is our customized com.atguigu.shiro.realm.MyRealm

7. org.apache.shiro.authc.pam.ModularRealmAuthenticator#doSingleRealmAuthentication. Call realm.getAuthenticationInfo(token) here to verify whether the username and password in the token are legal (usually compared with the username and password in the database) , if the comparison is consistent, it is legal)

8. org.apache.shiro.realm.AuthenticatingRealm#getAuthenticationInfo

9. org.apache.shiro.realm.AuthenticatingRealm#doGetAuthenticationInfo

The specific implementation is: com.atguigu.shiro.realm.MyRealm#doGetAuthenticationInfo

From the inheritance diagram, the Bean object defaultWebSecurityManager() in the project com.atguigu.shiro.config.ShiroConfig configuration shows that the customized DefaultWebSecurityManager is a subclass of Article 4 AuthenticatingSecurityManager.

 @Bean
    public DefaultWebSecurityManager defaultWebSecurityManager(){
        //1Create defaultWebSecurityManager object
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        //2Create an encrypted object and set related properties
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        //2.1 uses md5 encryption
        matcher.setHashAlgorithmName("md5");
        //2.2 Number of iteration encryption times
        matcher.setHashIterations(3);
        //3 Store the encrypted object into myRealm
        myRealm.setCredentialsMatcher(matcher);
        //4Save myRealm into the defaultWebSecurityManager object
        defaultWebSecurityManager.setRealm(myRealm);
        //4.5Set rememberMe
        defaultWebSecurityManager.setRememberMeManager(rememberMeManager());
        //4.6 Set cache manager
        defaultWebSecurityManager.setCacheManager(getEhCacheManager());

        //5return
        return defaultWebSecurityManager;
    }
The three methods used in configuration: setRealm(), setRememberMeManager(), and setCacheManager() are all defined in the parent class.
//4Save myRealm into the defaultWebSecurityManager object
defaultWebSecurityManager.setRealm(myRealm);
//4.5Set rememberMe
defaultWebSecurityManager.setRememberMeManager(rememberMeManager());
//4.6 Set cache manager
defaultWebSecurityManager.setCacheManager(getEhCacheManager());

Therefore, in shiro’s username and password verification process, when calling AuthenticatingSecurityManager#authenticate, shiro can find the implementation object defaultWebSecurityManager and its configured realm object myRealm based on the inheritance relationship, and execute the method of myRealm.