java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Shiro框架认证流程

Java的Shiro框架认证流程详解

作者:Splaying

这篇文章主要介绍了Java的Shiro框架认证流程详解,Shiro 是一个功能强大和易于使用的安全框架,为开发人员提供一个直观而全面的解决方案的认证,授权,加密,会话管理四大功能,需要的朋友可以参考下

1、Shiro框架介绍

在这里插入图片描述

2、入门案例

2.1、项目依赖

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-core</artifactId>
    <version>1.7.1</version>
</dependency>

2.2、模拟数据

[users]
zhangsan=123
admin=123456
splay=123456

2.3、案例

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.text.IniRealm;
import org.apache.shiro.subject.Subject;
public class Application {
    public static void main(String[] args) {
        // 1. 创建安全管理器对象
        DefaultSecurityManager securityManager = new DefaultSecurityManager();
        // 2. 给安全管理器对象设置realm(模拟数据库中的数据)
        securityManager.setRealm(new IniRealm("classpath:shiro.ini"));
        // 3. SecurityUtil设置全局的安全管理器
        SecurityUtils.setSecurityManager(securityManager);
        // 4. 关键对象Subject主体对象
        Subject subject = SecurityUtils.getSubject();
        // 5. 模拟登录(用户名、密码)
        UsernamePasswordToken user = new UsernamePasswordToken("splay", "123456");
        try{
            System.out.println("认证状态: " + subject.isAuthenticated());
            //登录校验
            subject.login(user);
            System.out.println("认证状态: " + subject.isAuthenticated());
        } catch (IncorrectCredentialsException e){
            e.printStackTrace();
            System.out.println("认证失败: 用户名密码错误!");
        } catch (UnknownAccountException e){
            e.printStackTrace();
            System.out.println("认证失败: 用户名错误!");
        }
    }
}

3、源码解析

3.1、用户名校验

public class SimpleAccountRealm extends AuthorizingRealm {
	protected SimpleAccount getUser(String username) {
	    USERS_LOCK.readLock().lock();				//ReentrantReadWriteLock可重入读写锁
	    try {
	        return this.users.get(username);
	    } finally {
	        USERS_LOCK.readLock().unlock();
	    }
	}
	
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)  {
	    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 new ExpiredCredentialsException(msg);
	        }
	    }
	    return account;
	}
}

3.2、密码校验

当用户校验返回值不为空时说明账户存在、没有被锁定、证书没有过期时进行密码校验。

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) {
            assertCredentialsMatch(token, info);		//见下方
        } else {
            log.debug("No AuthenticationInfo found for submitted AuthenticationToken [{}].  Returning null.", token);
        }

        return info;
    }
    protected void assertCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) throws AuthenticationException {
        CredentialsMatcher cm = getCredentialsMatcher();
        if (cm != null) {
            if (!cm.doCredentialsMatch(token, info)) {
                // 密码错误异常
                String msg = "Submitted credentials for token [" + token + "] did not match the expected credentials.";
                throw new IncorrectCredentialsException(msg);
            }
        } else {
            throw new AuthenticationException("A CredentialsMatcher must be configured in order to verify " +
                    "credentials during authentication.  If you do not wish for credentials to be examined, you " +
                    "can configure an " + AllowAllCredentialsMatcher.class.getName() + " instance.");
        }
    }
}

3.3、账户不存在异常

这里调用3.2中的方法、3.2中的调用3.1;实则Shiro封装了很多层这里只是最重要的代码。

public class ModularRealmAuthenticator extends AbstractAuthenticator {
	protected AuthenticationInfo doSingleRealmAuthentication(Realm realm, AuthenticationToken token) {
        if (!realm.supports(token)) {
            String msg = "Realm [" + realm + "] does not support authentication token [" +
                    token + "].  Please ensure that the appropriate Realm implementation is " +
                    "configured correctly or that the realm accepts AuthenticationTokens of this type.";
            throw new UnsupportedTokenException(msg);
        }
        AuthenticationInfo info = realm.getAuthenticationInfo(token);
        if (info == null) {
            String msg = "Realm [" + realm + "] was unable to find account data for the " +
                    "submitted AuthenticationToken [" + token + "].";
            throw new UnknownAccountException(msg);			//账户不存在
        }
        return info;
    }
}

到此这篇关于Java的Shiro框架认证流程详解的文章就介绍到这了,更多相关Shiro框架认证流程内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文