003-shiro认证

目录

认证顺序

ModularRealmAuthenticator(认证者)

AuthenticationStrategy(认证策略)

Shiro有3种具体的AuthenticationStrategy实现方式

自定义认证策略

领域认证顺序

隐式顺序

显示指定顺序

示例程序

示例1

示例2

示例3


认证顺序

  • 步骤1:应用程序代码调用该Subject.login方法,并传入AuthenticationToken表示最终用户的主体和凭据的构造实例。
  • 第2步:Subject实例(通常是一个DelegatingSubject(或子类))通过调用SecurityManager的securityManager.login(token)方法开始实际的身份验证工作。
  • 步骤3:SecurityManager作为基本的组件,接收令牌,并通过调用Authenticator来简单地委派给其内部实例authenticator.authenticate(token)。shiro支持我们定义多个Realm,然后通过ModularRealmAuthenticator实例,在身份验证期间协调一个或多个实例。
  • 步骤4:如果为该应用程序配置了多个Realm,则shiro的ModularRealmAuthenticator实例将Realm使用其configureed发起多次身份验证尝试AuthenticationStrategy(认证策略)。在Realms调用进行身份验证之前,期间和之后,将调用,AuthenticationStrategy以允许它对每个Realm的结果做出反应。
    • 如果仅配置一个Realm,则将直接调用该Realm。不需要调用AuthenticationStrategy。(我们的HelloWorld就是单个Realm,我们实际开发中大多数情况下也是单个Realm)
  • 第5步:Realm咨询每个配置,以查看是否supports(支持)已提交AuthenticationToken。如果是这样,则支持Realm的getAuthenticationInfo方法将与Submitted一起调用token。该getAuthenticationInfo方法有效地表示针对该特定对象的单个身份验证尝试Realm。(这里Realm的getAuthenticationInfo方法我们先记住,之后的自定义会用到)

ModularRealmAuthenticator(认证者)

在单一领域的应用程序中,ModularRealmAuthenticatorRealm直接调用单一领域。如果配置了两个或更多领域,它将使用一个AuthenticationStrategy实例来协调尝试的发生方式。

shiro默认使用ModularRealmAuthenticator,我们也可以自定义实现。自定义实现后通过shiro.ini直接设置(代码设置方式我想不用多说了把):

[main]
...
authenticator = com.foo.bar.CustomAuthenticator

securityManager.authenticator = $authenticator

AuthenticationStrategy(认证策略)

当为一个应用程序配置两个或多个领域时,ModularRealmAuthenticator依赖于内部AuthenticationStrategy组件来确定认证尝试成功或失败的条件。

AuthenticationStrategy是无状态组件,在尝试进行身份验证时会被查询4次:

  1. 在任何领域被调用之前
  2. 在getAuthenticationInfo调用单个Realm方法之前
  3. 在getAuthenticationInfo调用单个Realm方法之后
  4. 在所有领域都被调用之后

另外,AuthenticationStrategy负责将每个成功Realm的结果汇总并“捆绑”成一个单一的AuthenticationInfo表示形式。这个最终的聚合AuthenticationInfo实例是该Authenticator实例返回的内容,也是Shiro用来表示Subject的最终身份(又称为Principals)的东西。

Shiro有3种具体的AuthenticationStrategy实现方式

AuthenticationStrategy策略实现类描述
AtLeastOneSuccessfulStrategy(默认)如果一个(或多个)领域成功认证,则整个尝试都被视为成功。如果没有成功进行身份验证,则尝试将失败。(有一个成功则成功)
FirstSuccessfulStrategy仅使用从第一个成功通过身份验证的领域返回的信息。所有其他领域将被忽略。如果没有成功通过身份验证,则尝试将失败。(第一个成功即返回)
AllSuccessfulStrategy所有配置的领域都必须成功进行身份验证,才能将整体尝试视为成功。如果任何人未成功通过身份验证,则尝试将失败。(全部成功才成功)

 

 

 

 

自定义认证策略

以上3中策略实现已经基本满足了我们的要求,当然我们也可以自定义认证策略。首先继承实现org.apache.shiro.authc.pam.AbstractAuthenticationStrategy类,然后在shiro.int文件中配置:

[main]

authcStrategy = org.apache.shiro.authc.pam.FirstSuccessfulStrategy

securityManager.authenticator.authenticationStrategy = $authcStrategy

领域认证顺序

隐式顺序

在shiro.ini文件中认证顺序是从上到下

blahRealm = com.company.blah.Realm
...
fooRealm = com.company.foo.Realm
...
barRealm = com.company.another.Realm

显示指定顺序

通过securityManager.realms方法显示的指定顺序(注意:当你使用了显示指定后,比如你定义了3个Realm,但是securityManager.realms指定时只传入了两个,那么只有这两个会生效)

securityManager.realms = $blahRealm, $fooRealm, $barRealm

示例程序

shiro1.ini文件配置


[users]
user1 = password

shiro2.ini文件配置


[users]
user2 = password

示例1

package com.yyoo.mytest.shiro1.demo;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.realm.text.IniRealm;
import org.apache.shiro.subject.Subject;

import java.util.ArrayList;
import java.util.List;

public class Demo2 {

    public static void main(String[] args) {

        // 定义多个领域
        Realm realm1 = new IniRealm("classpath:shiro1.ini");
        Realm realm2 = new IniRealm("classpath:shiro2.ini");

        List<Realm> realms = new ArrayList<Realm>(2);
        realms.add(realm1);
        realms.add(realm2);

        SecurityManager securityManager = new DefaultSecurityManager(realms);
        SecurityUtils.setSecurityManager(securityManager);

        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken("user2","password");
        subject.login(token);

        System.out.println(subject.isAuthenticated());

        // 没有设定认证策略,将使用默认策略AtLeastOneSuccessfulStrategy,有一个成功即成功,所以user1和user2都能够正常登录

    }

}

示例2

package com.yyoo.mytest.shiro1.demo;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.pam.FirstSuccessfulStrategy;
import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.realm.text.IniRealm;
import org.apache.shiro.subject.Subject;

import java.util.ArrayList;
import java.util.List;

public class Demo3 {

    public static void main(String[] args) {

        // 定义多个领域
        Realm realm1 = new IniRealm("classpath:shiro1.ini");
        Realm realm2 = new IniRealm("classpath:shiro2.ini");

        List<Realm> realms = new ArrayList<Realm>(2);
        realms.add(realm1);
        realms.add(realm2);

        DefaultSecurityManager securityManager = new DefaultSecurityManager(realms);
        SecurityUtils.setSecurityManager(securityManager);

        System.out.println(securityManager.getAuthenticator());
        ModularRealmAuthenticator authenticator = (ModularRealmAuthenticator)securityManager.getAuthenticator();
        // 设置认证策略
        authenticator.setAuthenticationStrategy(new FirstSuccessfulStrategy());

        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken("user2","password");
        subject.login(token);

        System.out.println(subject.isAuthenticated());

        // 使用策略FirstSuccessfulStrategy,第一个成功就返回(因为两个Realm)
        /**
         * user1登录,执行了Realm1即停止
         * user2登录,执行了Realm1和Realm2,执行Realm2成功即停止
         */

    }

}

示例3

package com.yyoo.mytest.shiro1.demo;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.pam.AllSuccessfulStrategy;
import org.apache.shiro.authc.pam.FirstSuccessfulStrategy;
import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.realm.text.IniRealm;
import org.apache.shiro.subject.Subject;

import java.util.ArrayList;
import java.util.List;

public class Demo4 {

    public static void main(String[] args) {

        // 定义多个领域
        Realm realm1 = new IniRealm("classpath:shiro1.ini");
        Realm realm2 = new IniRealm("classpath:shiro2.ini");

        List<Realm> realms = new ArrayList<Realm>(2);
        realms.add(realm1);
        realms.add(realm2);

        DefaultSecurityManager securityManager = new DefaultSecurityManager(realms);
        SecurityUtils.setSecurityManager(securityManager);

        System.out.println(securityManager.getAuthenticator());
        ModularRealmAuthenticator authenticator = (ModularRealmAuthenticator)securityManager.getAuthenticator();
        // 设置认证策略
        authenticator.setAuthenticationStrategy(new AllSuccessfulStrategy());

        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken("user2","password");
        subject.login(token);

        System.out.println(subject.isAuthenticated());

        // 使用策略AllSuccessfulStrategy,全部成功才算成功
        /**
         * 由于两个Realm的用户都不一致,所以使用该策略,user1和user2都不能正常登录
         */


    }

}

上一篇:002-shiro的HelloWorld入门

下一篇:004-授权策略

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值