Shiro认证流程

161 阅读2分钟
1. 认证

身份认证,就是判断一个用户是否为合法用户的处理过程。最常用的简单身份认证方式是系统通过核对用户输入的用户名和口令,看其是否与系统中存储的该用户的用户名和口令一致,来判断用户身份是否正确。

2. shiro中认证的关键对象
  • Subject:主体

    访问系统的用户,主体可以是用户、程序等,进行认证的都称为主体;

  • Principal:身份信息

    是主体(subject)进行身份认证的标识,标识必须具有唯一性,如用户名、手机号、邮箱地址等,一个主体可以有多个身份,但是必须有一个主身份(Primary Principal)。

  • credential:凭证信息

    是只有主体自己知道的安全信息,如密码、证书等。

3. 认证流程

4. 认证的开发
4.1 引入依赖
<dependency>
  <groupId>org.apache.shiro</groupId>
  <artifactId>shiro-core</artifactId>
  <version>1.5.3</version>
</dependency>
4.2 自定义Realm

shiro提供的Realm

/**
 * 自定义realm
 */
public class CustomerRealm extends AuthorizingRealm {
    // 授权方法
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        return null;
    }

    // 认证方法
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String principal = (String) token.getPrincipal();
        if("whw".equals(principal)){
            return new SimpleAuthenticationInfo(principal, "123", this.getName());
        }
        return null;
    }
}
4.3 使用自定义Realm认证
public class TestAuthenticatorCusttomerRealm {
    public static void main(String[] args) {
        // 创建securityManager
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();

        // 设置为自定义realm获取认证数据
        defaultSecurityManager.setRealm(new CustomerRealm());

        // 将安装工具类中设置默认安全管理器
        SecurityUtils.setSecurityManager(defaultSecurityManager);

        // 获取主体对象
        Subject subject = SecurityUtils.getSubject();

        // 创建token令牌
        UsernamePasswordToken token = new UsernamePasswordToken("whw", "123");
        try {
            // 用户登录
            subject.login(token);
            System.out.println("登录成功!");
        } catch (UnknownAccountException e) {
            e.printStackTrace();
            System.out.println("用户名错误!!");
        }catch (IncorrectCredentialsException e){
            e.printStackTrace();
            System.out.println("密码错误!!!");
        }

    }
}
4.4 使用MD5和Salt

实际应用是将盐和散列后的值存在数据库中,自动realm从数据库取出盐和加密后的值由shiro完成密码校验。

/**
 * 自定义md5+salt realm
 */
public class CustomerRealm extends AuthorizingRealm {
    // 授权方法
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        return null;
    }

    // 认证方法
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String principal = (String) token.getPrincipal();
        if("whw".equals(principal)){
            String password = "3c88b338102c1a343bcb88cd3878758e";
            String salt = "Q4F%";
            return new SimpleAuthenticationInfo(principal, password, ByteSource.Util.bytes(salt), this.getName());
        }
        return null;
    }

使用md5 + salt 认证

public class TestAuthenticatorCusttomerRealm {
    public static void main(String[] args) {
        // 创建securityManager
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        // 设置为自定义realm获取认证数据
        CustomerRealm customerRealm = new CustomerRealm();

        // 设置md5加密
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        credentialsMatcher.setHashAlgorithmName("MD5");
        // 设置散列次数
        credentialsMatcher.setHashIterations(1024);
        customerRealm.setCredentialsMatcher(credentialsMatcher);
        defaultSecurityManager.setRealm(customerRealm);

        // 将安装工具类中设置默认安全管理器
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        // 获取主体对象
        Subject subject = SecurityUtils.getSubject();
        // 创建token令牌
        UsernamePasswordToken token = new UsernamePasswordToken("whw", "123");
        try {
            // 用户登录
            subject.login(token);
            System.out.println("登录成功!");
        } catch (UnknownAccountException e) {
            e.printStackTrace();
            System.out.println("用户名错误!!");
        }catch (IncorrectCredentialsException e){
            e.printStackTrace();
            System.out.println("密码错误!!!");
        }

    }
}