realm
Copy the code

Realm: Shiro gets security data (such as users, roles, and permissions) from a Realm. This means that SecurityManager needs to authenticate the user, then it needs to get the corresponding user from the Realm and compare it to determine if the user is valid. You also need to get the user’s roles/permissions from the Realm to verify that the user can perform operations. You can configure more than one, but at least one

Realm’s status can be seen in Shiro’s top-level architecture diagramRelam has a lot of general inheritance AuthorizingRealm and can also inherit other realm classes as required

Public Class MyRealm extends AuthorizingRealm {/** * Grant ** @param principals * @Return */ @override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { return null; } /** * Authentication ** @param token * @return * @Throws AuthenticationException */ @Override Protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { return null; }}Copy the code

Authentication: Simply login. How does Shiro log in? (MindManager Mind Mapping)

A quick word about the login process:

Click Login to submit the user name and password to controller

Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken(username, password); subject.login(token); `Copy the code

Call DelegatingSubject. Login

public class DelegatingSubject implements Subject public void login(AuthenticationToken token) throws AuthenticationException { clearRunAsIdentitiesInternal(); // Call securityManager.login(this, token); Subject subject = securityManager.login(this, token); PrincipalCollection principals; String host = null; if (subject instanceof DelegatingSubject) { DelegatingSubject delegating = (DelegatingSubject) subject; //we have to do this in case there are assumed identities - we don't want to lose the 'real' principals: principals = delegating.principals; host = delegating.host; } else { principals = subject.getPrincipals(); } if (principals == null || principals.isEmpty()) { String msg = "Principals returned from securityManager.login( token ) returned a null or " + "empty value. This value must be non null and populated with one or more elements."; throw new IllegalStateException(msg); } this.principals = principals; this.authenticated = true; if (token instanceof HostAuthenticationToken) { host = ((HostAuthenticationToken) token).getHost(); } if (host ! = null) { this.host = host; } Session session = subject.getSession(false); if (session ! = null) { this.session = decorate(session); } else { this.session = null; }}Copy the code

Call DefaultSecurityManager. Login

public class DefaultSecurityManager extends SessionsSecurityManager 
 
 
public Subject login(Subject subject, AuthenticationToken token) throws AuthenticationException {
    AuthenticationInfo info;
    try {
        info = authenticate(token);
    } catch (AuthenticationException ae) {
        try {
            onFailedLogin(token, ae, subject);
        } catch (Exception e) {
            if (log.isInfoEnabled()) {
                log.info("onFailedLogin method threw an " +
                        "exception.  Logging and propagating original AuthenticationException.", e);
            }
        }
        throw ae; //propagate
    }

    Subject loggedIn = createSubject(token, info, subject);

    onSuccessfulLogin(token, info, loggedIn);

    return loggedIn;
}
 
 
/**
 * Delegates to the wrapped {@link org.apache.shiro.authc.Authenticator Authenticator} for authentication.
 */
public AuthenticationInfo authenticate(AuthenticationToken token) throws AuthenticationException {
    return this.authenticator.authenticate(token);
}

Copy the code

AuthenticatingSecurityManager.authenticate

public abstract class AuthenticatingSecurityManager extends RealmSecurityManager { private Authenticator authenticator; /** * Default no-arg constructor that initializes its internal * <code>authenticator</code> instance to a * {@link org.apache.shiro.authc.pam.ModularRealmAuthenticator ModularRealmAuthenticator}. */ public AuthenticatingSecurityManager() { super(); this.authenticator = new ModularRealmAuthenticator(); } /** * Delegates to the wrapped {@link org.apache.shiro.authc.Authenticator Authenticator} for authentication. */ public AuthenticationInfo authenticate(AuthenticationToken token) throws AuthenticationException { return this.authenticator.authenticate(token); }}Copy the code

AbstractAuthenticator .authenticate

public abstract class AbstractAuthenticator implements Authenticator, LogoutAware { public final AuthenticationInfo authenticate(AuthenticationToken token) throws AuthenticationException { if (token == null) { throw new IllegalArgumentException("Method argument (authentication token) cannot be null."); } log.trace("Authentication attempt received for token [{}]", token); AuthenticationInfo info; try { info = doAuthenticate(token); if (info == null) { String msg = "No account information found for authentication token [" + token + "] by this " + "Authenticator instance. Please check that it is configured correctly."; throw new AuthenticationException(msg); } } catch (Throwable t) { AuthenticationException ae = null; if (t instanceof AuthenticationException) { ae = (AuthenticationException) t; } if (ae == null) { //Exception thrown was not an expected AuthenticationException. Therefore it is probably a little more //severe or unexpected. So, wrap in an AuthenticationException, log to warn, and propagate: String msg = "Authentication failed for token submission [" + token + "]. Possible unexpected " + "error? (Typical or expected login exceptions should extend from AuthenticationException)."; ae = new AuthenticationException(msg, t); if (log.isWarnEnabled()) log.warn(msg, t); } try { notifyFailure(token, ae); } catch (Throwable t2) { if (log.isWarnEnabled()) { String msg = "Unable to send notification for failed authentication attempt - listener error? . " + "Please check your AuthenticationListener implementation(s). Logging sending exception " + "and propagating original AuthenticationException instead..." ; log.warn(msg, t2); } } throw ae; } log.debug("Authentication successful for token [{}]. Returned account [{}]", token, info); notifySuccess(token, info); return info; } protected abstract AuthenticationInfo doAuthenticate(AuthenticationToken token) throws AuthenticationException; }Copy the code

ModularRealmAuthenticator.doAuthenticate

public class ModularRealmAuthenticator extends AbstractAuthenticator { protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException { assertRealmsConfigured(); Collection<Realm> realms = getRealms(); if (realms.size() == 1) { return doSingleRealmAuthentication(realms.iterator().next(), authenticationToken); } else { return doMultiRealmAuthentication(realms, authenticationToken); }}}Copy the code

Shiro judgment configuration of realm is a certification or multiple calls a different way But will be called AuthenticatingRealm getAuthenticationInfo

public abstract class AuthenticatingRealm extends CachingRealm implements Initializable { public final AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { AuthenticationInfo info = getCachedAuthenticationInfo(token); if (info == null) { //otherwise not cached, perform the lookup: info = doGetAuthenticationInfo(token); log.debug("Looked up AuthenticationInfo [{}] from doGetAuthenticationInfo", info); if (token ! = null && info ! = null) { cacheAuthenticationInfoIfPossible(token, info); } } else { log.debug("Using cached authentication info [{}] to perform credentials matching.", info); } if (info ! = null) {// Password comparison mainly depends on password encryption assertCredentialsMatch(token, info); } else { log.debug("No AuthenticationInfo found for submitted AuthenticationToken [{}]. Returning null.", token); } return info; } protected abstract AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException;Copy the code

Custom realm

Public class MyRealm extends AuthorizingRealm {// Public class MyRealm extends AuthenticatingRealm {/** * AuthenticatingRealm ** @param  token * @return * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token; String username = usernamePasswordToken.getUsername(); String password = String.valueOf(usernamePasswordToken.getPassword()); ByteSource solt = ByteSource.Util.bytes(username); if (username.equals("username") && password.equals("password")) { return new SimpleAuthenticationInfo(username, password, getName()); } return null; }}Copy the code

It involves more than a realm and the realm see ModularRealmAuthenticator source code analysis and configuration