1. 创建项目并引入依赖
  1. <dependency>
  2. <groupId>org.apache.shiro</groupId>
  3. <artifactId>shiro-core</artifactId>
  4. <version>1.5.3</version>
  5. </dependency>

2. 引入shiro配置文件

配置文件:名称随意,以 .ini 结尾,放在 resources 目录下

注意:在实际的项目开发中并不会使用这种方式,这种方法可以用来初学时练手

  1. [users]
  2. jack=123
  3. marry=456
  4. alice=789

image.png

3.开发认证代码
package com.cedric;

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.realm.text.IniRealm;
import org.apache.shiro.subject.Subject;

public class TestAuthenticator {
    public static void main(String[] args) {

        //1.创建安全管理器对象
        DefaultSecurityManager securityManager = new DefaultSecurityManager();

        //2.给安全管理器设置realm
        securityManager.setRealm(new IniRealm("classpath:shiro.ini"));

        //3.SecurityUtils给全局安全工具类设置安全管理器
        SecurityUtils.setSecurityManager(securityManager);

        //4.关键对象  subject主体
        Subject subject = SecurityUtils.getSubject();

        //5.创建令牌
        UsernamePasswordToken token = new UsernamePasswordToken("jack","123");

        try{
            subject.login(token);    // 用户认证
            System.out.println("认证状态:" + subject.isAuthenticated());
        } catch (UnknownAccountException e){
            e.printStackTrace();
            System.out.println("认证失败:用户名不存在");
        } catch (IncorrectCredentialsException e){
            e.printStackTrace();
            System.out.println("认证失败:密码错误");
        }
    }
}

4.常见的异常类型
  • DisabledAccountException(帐号被禁用)
  • LockedAccountException(帐号被锁定)
  • ExcessiveAttemptsException(登录失败次数过多)
  • ExpiredCredentialsException(凭证过期)等


4.5 自定义Realm

通过分析源码可得:

认证:

1.最终执行用户名比较是 在SimpleAccountRealm类 的 doGetAuthenticationInfo 方法中完成用户名校验

2.最终密码校验是在 AuthenticatingRealm类 的 assertCredentialsMatch方法 中

总结:

AuthenticatingRealm 认证realm doGetAuthenticationInf

AuthorizingRealm 授权realm doGetAuthorizationInfo

自定义Realm的作用:放弃使用.ini文件,使用数据库查询

上边的程序使用的是Shiro自带的IniRealm,IniRealm从ini配置文件中读取用户的信息,大部分情况下需要从系统的数据库中读取用户信息,所以需要自定义realm。

4.5.1.shiro提供的Realm
image.png

根据认证源码认证使用的是SimpleAccountRealm

image.png

SimpleAccountRealm的部分源码中有两个方法一个是 认证 一个是 授权

源码部分:

public class SimpleAccountRealm extends AuthorizingRealm {
        //.......省略
    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 new ExpiredCredentialsException(msg);
            }

        }

        return account;
    }

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