3、Shiro实现认证

基本概念

  • 身份验证

    即在应用中谁能证明他就是他本人。一般提供如他们的身份ID 一些标识信息来表明他就是他本人,如提供身份证,用户名/密码来证明。

    在 shiro 中,用户需要提供principals(身份)和credentials(证明)给shiro,从而应用能验证用户身份。

  • principals(身份)

    身份,即主体的标识属性,可以是任何东西,如用户名、邮箱等,唯一即可。 一个主体可以有多个principals,但只有一个Primary principals,一般是用户名/密码/手机号。

  • credentials(证明)

    证明/凭证,即只有主体知道的安全值,如密码/数字证书等。 最常见的principals和credentials组合就是用户名/密码了。

认证流程

3、Shiro实现认证

1、调用Subject.login(token)进行登录,其会自动委托给Security Manager,调用之前必须通过SecurityUtils.setSecurityManager()设置。

2、Security Manager负责真正的身份验证逻辑,它会委托给Authenticator进行身份验证。

3、Authenticator才是真正的身份验证者,Shiro API中核心的身份认证入口点,此处可以自定义自己的实现。

4、Authenticator可能会委托给相应的AuthenticationStrategy进行多Realm身份验证,默认ModularRealmAuthenticator会调用AuthenticationStrategy进行多Realm身份验证。

5、Authenticator会把相应的token传入Realm,从Realm获取身份验证信息,如果没有返回/抛出异常表示身份验证失败。此处可以配置多个Realm,将按照相应的顺序及策略进行访问。

入门程序实现认证

1、创建项目,创建普通的Maven工程。

2、在pom.xml中导入依赖

<!-- shiro核心包 -->
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-core</artifactId>
    <version>1.4.0</version>
</dependency>
<!-- 日志 -->
<dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.2</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.6.6</version>
</dependency>

3、log4j.properties日志配置文件

log4j.rootLogger=debug, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m %n

4、在src/java/resources下新建shiro.ini文件

# 配置用户名和密码
[users]
zhangsan=123456
lisi=123456

5、编写代码实现认证

package com.coydone.test;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;

public class AuthUserTeat {
    public static void main(String[] args) {
        //1、接收用户名和密码
        String username = "zhangsan";
        String password = "123456";

        //2、把用户名和密码封装
        UsernamePasswordToken token = new UsernamePasswordToken(username,password);

        //3、创建安全管理器的工厂
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");

        //4、从Factory中得到安全管理器
        SecurityManager securityManager = factory.getInstance();

        //5、把securityManager和Subject绑定到当前线程
        SecurityUtils.setSecurityManager(securityManager);

        //6、从SecurityUtils中得到subject
        Subject subject = SecurityUtils.getSubject();

        //7、去认证
        try {
            subject.login(token);
            System.out.println("认证通过");
        } catch (AuthenticationException e) {
            System.out.println("用户名或密码不正确");
        }
        /*
        catch (IncorrectCredentialsException e) {
            System.out.println("密码不正确");
        } catch (UnknownAccountException e) {
            System.out.println("用户名不存在");
        }
         */

        //8、查看认证状态
        System.out.println("认证状态:"+subject.isAuthenticated());

        //9、退出
        subject.logout();
        System.out.println("认证状态:"+subject.isAuthenticated());
    }
}

自定义Realm完成认证

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

3、Shiro实现认证

最基础的是Realm接口,CachingRealm负责缓存处理,AuthenticationRealm负责认证,AuthorizingRealm负责授权,通常自定义的realm继承AuthorizingRealm。

1、自定义UserRealm

package com.coydone.realm;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

public class UserRealm extends AuthorizingRealm {

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //1、得到身份
        String username = token.getPrincipal().toString();
        //得到凭证
        //String password = token.getCredentials().toString();

        //在shiro里面是先根据用户名把用户对象查询出来,再来做密码匹配

        //2,根据用户名到数据库中取出用户信息  如果查询不到 返回null  可以使用service来查
        String password = "123456";//假如从数据库中获取密码为1111

        //3,返回认证信息
        /**
         * 参数1:可以传到任意对象,如果登录成功,会调用doGetAuthorizationInfo去授权
         * 参数2:从数据库里面查询出来的密码
         * 参数3:当前类名
         */
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(username, password, this.getName());
        return simpleAuthenticationInfo;
    }
    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }
}

2、配置shiro.ini文件

# 作全局配置
[main]
# 创建UserRealm的对象
userRealm=com.coydone.realm.UserRealm
# 创建默认的安全管理器
securityManager=org.apache.shiro.mgt.DefaultSecurityManager
# 把userRealm给安全管理器
securityManager.realms=$userRealm

3、测试(测试代码同上)

public class AuthUserTeat {}