certification

Identity authentication is the process of determining whether a user is a legitimate user. The most common simple authentication method is that the system checks whether the user name and password entered by the user are consistent with the user name and password stored in the system to determine whether the user identity is correct.

Key object for Shiro certification

  • Subjects can be users, applications, and so on accessing the system. Anything that needs to be authenticated is called a principal.
  • Principal: The identity information used by the Subject for identity authentication. The identity must be unique. For example, the user name, mobile phone number, and email address. A Principal can have multiple identities, but there must be one Primary Principal.
  • Credential: security information, such as passwords and certificates, that only the subject knows.

Shiro certification process

The user authenticates with identity and credential information (typically a username and password), and Shiro packages the information we provide into a Token, which is then sent to Shiro’s Security Manager for verification. The verification process is as follows: The Security Manager calls the Authenticator, and the Authenticator calls Pluggable Realms to get the raw data. Then the raw data is matched with the user-provided information. If the data is consistent, the authentication succeeds.

The Demo Shrio certification

  1. Introduce dependencies in POM.xml

    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-core</artifactId>
        <version>1.5.3</version>
    </dependency>
    Copy the code
  2. Create the shiro.ini file in the Resources directory

    [users]
    john=123
    peter=12345
    Copy the code

    Ini is a configuration file in Shiro that can write system permission data in the INI file when there is no connection to the database.

  3. Demo

    public static void main(String[] args) {
        DefaultSecurityManager is a concrete implementation of the SecurityManager interface
        DefaultSecurityManager securityManager = new DefaultSecurityManager();
    
        // Set the security manager to Realm for identity and credential data
        securityManager.setRealm(new IniRealm("classpath:shiro.ini"));
    
        // Global security tool class provided by Shiro SecurityUtils Security tool Sets the security manager for authentication
        SecurityUtils.setSecurityManager(securityManager);
    
        // Key object Subject Subject of the current login
        Subject subject = SecurityUtils.getSubject();
    
        // Create a token with the identity information as username
        UsernamePasswordToken token = new UsernamePasswordToken("john"."123");
    
        try {
            // User authentication If the authentication succeeds, no exception will be thrown
            subject.login(token);
            // Obtain the authentication status. True indicates that the authentication succeeds. False indicates that the authentication fails
            System.out.println("Certification Status:" + subject.isAuthenticated());
        } catch (UnknownAccountException e) {
            The user name does not exist
            e.printStackTrace();
        } catch (IncorrectCredentialsException e) {
            // Authentication failed. The password is incorrecte.printStackTrace(); }}Copy the code

Shiro certified source code

The Demo uses Shiro’s lniRealm. IniRealm reads user information from the INI configuration file. In most cases, you need to read user information from the system database, so you need to customize the Realm.

Shiro provides the following system Realm:

Realms designed for authentication are as follows:

The SimpleAccountRealm class is the low-level authentication and authorization operations that Shiro does by default, with the doGetAuthenticationInfo method handling authentication and the doGetAuthorizationInfo method handling authorization.

public class SimpleAccountRealm extends AuthorizingRealm {...// Authentication processing
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        UsernamePasswordToken upToken = (UsernamePasswordToken) token;
        SimpleAccount account = getUser(upToken.getUsername());

        if(account ! =null) {

            if (account.isLocked()) {
                throw new LockedAccountException("Account [" + account + "] is locked.");
            }
            if (account.isCredentialsExpired()) {
                String msg = "The credentials for account [" + account + "] are expired";
                throw newExpiredCredentialsException(msg); }}return account;
    }

    // Authorization processing
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String username = getUsername(principals);
        USERS_LOCK.readLock().lock();
        try {
            return this.users.get(username);
        } finally{ USERS_LOCK.readLock().unlock(); }}}Copy the code

The doGetAuthenticationInfo method defined in the SimpleAccountRealm class only handles authentication of identity information (user name). Authentication of passwords is handled automatically by Shiro.

Custom Authentication

If we want to change the mode of reading data from the INI configuration file to reading data from the database, we must define a class that inherits AuthorizingRealm and rewrite the doGetAuthenticationInfo method.

public class UserRealm extends AuthorizingRealm {

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        return null;
    }

    // Modify the authentication processing method
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        // Get the identity information
        String username = (String) token.getPrincipal();

        // Read data from the database for authentication and password authentication
        if ("john".equals(username)) {
            // Parameter 1: user name parameter 2: password parameter 3: current Realm name
            SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(username, "123".this.getName());
            
            // Successful authentication returns SimpleAuthenticationInfo
            return simpleAuthenticationInfo;
        }

        return null; }}Copy the code

Then modify the injected Realm

public static void main(String[] args) {
    DefaultSecurityManager securityManager = new DefaultSecurityManager();

    // Inject custom realms
    UserRealm userRealm = new UserRealm();
    securityManager.setRealm(userRealm);
    
    securityManager.setRealm(new IniRealm("classpath:shiro.ini"));

    SecurityUtils.setSecurityManager(securityManager);

    Subject subject = SecurityUtils.getSubject();

    UsernamePasswordToken token = new UsernamePasswordToken("john"."123");

    try {
        subject.login(token);
        System.out.println("Certification Status:" + subject.isAuthenticated());
    } catch (UnknownAccountException e) {
        e.printStackTrace();
    } catch(IncorrectCredentialsException e) { e.printStackTrace(); }}Copy the code