Spring Boot integrates shiro's salt value encryption authentication

summary

In the last blog, we mainly talked about custom Realm. The passwords used for user authentication are in clear text. This method is not desirable. Often, in our actual combat development, the user's passwords are stored in ciphertext, and the encryption algorithm is required to be irreversible. The famous encryption algorithms include MD5, SHA1, etc. So in this blog, we mainly introduce Shiro security framework and learn its encryption scheme. Here we use MD5 encryption, and then. MD5 encryption is divided into adding salt and not adding salt.

No salt certification

    @Test
    public void testMatcher() {
        CustomRealm customRealm = new CustomRealm();
        //1. Build a SecurityManager environment
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        //Set Realm
        defaultSecurityManager.setRealm(customRealm);
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        //Get principal
        Subject subject = SecurityUtils.getSubject();
        //token of user name and password
        UsernamePasswordToken token = new UsernamePasswordToken("dev", "123456");
        try {
            //2. The subject submits an authentication request
            subject.login(token);
            System.out.println("Whether authority authentication: isAuthenticated=" + subject.isAuthenticated());
            //Check for roles
            subject.checkRoles("admin");
            System.out.println("yes admin role");
            //Check for permissions
            subject.checkPermissions("user:delete", "user:edit", "user:list", "user:add");
            System.out.println("yes user:add,user:list,user:edit,user:delete jurisdiction");

        } catch (IncorrectCredentialsException exception) {
            System.out.println("Wrong user name or password");
        } catch (LockedAccountException exception) {
            System.out.println("Account locked");
        } catch (DisabledAccountException exception) {
            System.out.println("Account has been disabled");
        } catch (UnknownAccountException exception) {
            System.out.println("user does not exist");
        } catch (UnauthorizedException ae) {
            System.out.println("User does not have permission");
        }
    }

CustomRealm please refer to Spring Boot uses custom Realm for authentication and authorization (V)

Add password authentication core code

        //Encrypt
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        //md5 encryption
        matcher.setHashAlgorithmName("md5");
        //Set encryption times
        matcher.setHashIterations(2);
        customRealm.setCredentialsMatcher(matcher);

Modify the method of obtaining ciphertext in CustomRealm

     /**
     * Obtain ciphertext password
     * @Author:     djy
     * @UpdateUser:
     * @Version:     0.0.1
     * @param currentPassword
     * @return       java.lang.String
     * @throws
     */
    private String getPasswordMatcher(String currentPassword){
        return new Md5Hash(currentPassword, null,2).toString();
   }

Modify doGetAuthenticationInfo

    /**
     * User authentication
     *
     * @param authenticationToken
     * @return org.apache.shiro.authc.AuthenticationInfo
     * @throws
     * @Author: djy
     * @UpdateUser:
     * @Version: 0.0.1
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("Start execution*******doGetAuthenticationInfo Method****");
        //Get login user name
        String userName = (String) authenticationToken.getPrincipal();
        //Get user information from user name to database
        String password = getPasswordByUsername(userName);
        if (null == password) {
            return null;
        }
        System.out.println("Password is:" + password);
        String matcherPwd = getPasswordMatcher(password);
        System.out.println(matcherPwd);
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(userName, password, getName());
        return authenticationInfo;
    }

When the user admin logs in, the program outputs

UsernamePasswordToken token = new UsernamePasswordToken("admin", "123456");
  • Program output
Whether authority authentication: isAuthenticated=true
 Start execution*******doGetAuthorizationInfo Method****
admin
 yes admin role
 Start execution*******doGetAuthorizationInfo Method****
admin
 Start execution*******doGetAuthorizationInfo Method****
admin
 Start execution*******doGetAuthorizationInfo Method****
admin
 Start execution*******doGetAuthorizationInfo Method****
admin
 yes user:add,user:list,user:edit,user:delete jurisdiction
  • If it is changed, it is still tested in clear text
//       String matcherPwd=getPasswordMatcher(password);
//       System.out.println(matcherPwd);
//       SimpleAuthenticationInfo authenticationInfo = new 
//SimpleAuthenticationInfo(username,matcherPwd,getName());
        SimpleAuthenticationInfo authenticationInfo = new
SimpleAuthenticationInfo(username,password,getName());
  • Program output
Start execution*******doGetAuthenticationInfo Method****
Password: 123456
4280d89a5a03f812751f504cc10ee8a5
 Wrong user name or password

Salt certification

When the passwords of two users are the same, simply using MD5 encryption without salt will find that there are passwords with the same structure in the database, which is also unsafe. We hope that even if the original passwords of two people are the same, the encrypted results will be different. How? In fact, it's like cooking. Two courses of fish flavored shredded pork with different salt make it taste different. The same is true for MD5 encryption, which requires salt value encryption.

Create testSaltMatcher method

    @Test
    public void testSaltMatcher() {
        CustomRealm customRealm = new CustomRealm();
        //Encrypt
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        //mdf encryption
        matcher.setHashAlgorithmName("md5");
        //Set encryption times
        matcher.setHashIterations(1);
        customRealm.setCredentialsMatcher(matcher);
        //1. Build a SecurityManager environment
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        //Set Realm
        defaultSecurityManager.setRealm(customRealm);
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        //Get principal
        Subject subject = SecurityUtils.getSubject();
        //token of user name and password
        UsernamePasswordToken token = new UsernamePasswordToken("admin", "123456");
        try {
            //2. The subject submits an authentication request
            subject.login(token);
            System.out.println("Whether authority authentication: isAuthenticated=" + subject.isAuthenticated());
            //Check for roles
            subject.checkRoles("admin");
            System.out.println("yes admin role");
            //Check for permissions
            subject.checkPermissions("user:delete", "user:edit", "user:list", "user:add");
            System.out.println("yes user:add,user:list,user:edit,user:delete jurisdiction");
            //if no exception, that's it, we're done!
        } catch (IncorrectCredentialsException exception) {
            System.out.println("Wrong user name or password");
        } catch (LockedAccountException exception) {
            System.out.println("Account locked");
        } catch (DisabledAccountException exception) {
            System.out.println("Account has been disabled");
        } catch (UnknownAccountException exception) {
            System.out.println("user does not exist");
        } catch (UnauthorizedException ae) {
            System.out.println("User does not have permission");
        }
    }

Salt verification core code

//Set the value of the salt
 authenticationInfo.setCredentialsSalt(ByteSource.Util.bytes(username));

Modify CustomRealm and add a method to obtain salt ciphertext

    /**
     * Obtain ciphertext password
     *
     * @param currentPassword
     * @return java.lang.String
     * @throws
     * @Author: djy
     * @UpdateUser:
     * @Version: 0.0.1
     */
    private String getPasswordMatcher(String currentPassword, String username) {
        return new Md5Hash(currentPassword, username).toString();
    }

Modify doGetAuthenticationInfo

    /**
     * User authentication
     *
     * @param authenticationToken
     * @return org.apache.shiro.authc.AuthenticationInfo
     * @throws
     * @Author: djy
     * @UpdateUser:
     * @Version: 0.0.1
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("Start execution*******doGetAuthenticationInfo Method****");
        //Get login user name
        String userName = (String) authenticationToken.getPrincipal();
        //Get user information from user name to database
        String password = getPasswordByUsername(userName);
        if (null == password) {
            return null;
        }
//        System.out.println("password is:" + password);
//        String matcherPwd = getPasswordMatcher(password);
        String matcherPwd = getPasswordMatcher(password,userName);
        System.out.println(matcherPwd);
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(userName, matcherPwd, getName());
        //Set the value of the salt
        authenticationInfo.setCredentialsSalt(ByteSource.Util.bytes(userName));
        return authenticationInfo;
    }

test

  • When the user admin logs in, the program outputs
UsernamePasswordToken token = new UsernamePasswordToken("admin", "123456");
Start execution*******doGetAuthenticationInfo Method****
a66abb5684c45962d887564f08346e8d
 Whether authority authentication: isAuthenticated=true
 Start execution*******doGetAuthorizationInfo Method****
admin
 yes admin role
 Start execution*******doGetAuthorizationInfo Method****
admin
 Start execution*******doGetAuthorizationInfo Method****
admin
 Start execution*******doGetAuthorizationInfo Method****
admin
 Start execution*******doGetAuthorizationInfo Method****
admin
 yes user:add,user:list,user:edit,user:delete jurisdiction
  • When the user admin logs in, but the password is input into 1234567 program output
UsernamePasswordToken token = new UsernamePasswordToken("admin", "1234567");
Start execution*******doGetAuthenticationInfo Method****
a66abb5684c45962d887564f08346e8d
 Wrong user name or password
  • When the user admin logs in, the password is also entered correctly, but the plaintext program output is used for authentication
//Comment out the following two methods
//String matcherPwd = getPasswordMatcher(password,userName);
//System.out.println(matcherPwd);
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(username,password,getName());
Start execution*******doGetAuthenticationInfo Method****
Wrong user name or password

shiro encryption is all about here. In fact, some small partners will have questions. If our company uses sessionID as the login status certificate, what should we do and how can we make users pass authentication? Here, we can customize the password matching class, inherit the HashedCredentialsMatcher class, and override its doCredentialsMatch (password matching method). Later, when we explain the actual combat development, we will explain it in detail.

Keywords: Java Shiro Spring Boot

Added by Karve on Sun, 19 Sep 2021 07:29:36 +0300