学习shiro第三天
今天比较晚,所以只看了shiro的认证策略Authentication Strategy,下面讲讲shiro的三种认证策略。
1.AtLeastOneSuccessfulStrategy:这个是shiro默认的认证策略,它表示如果存在多个realm来执行认证,只要其中有一个成功,那么认证就成功(这里注意所有的realm都会进行验证,不管是失败还是成功);
2.AllSuccessfulStrategy:这个策略表示必须所有的realm认证成功才算最终认证成功,哪怕只有一个不成功,那么结果都为认证不成功。(这里也是会将所有的realm都进行验证);
3.FirstSuccessfulStrategy:它表示只要有一个realm中认证成功了,那么剩下的其它realm都不必进行验证了,直接返回认证成功。注意这里只要遇到第一个成功认证的realm,其他剩下的realm都不会被调用。
说了三种认证策略的概念,那么我们怎么进行配置认证策略呢?这个问题就要追溯到shiro中进行认证操作的认证器子类modularRealmAuthenticator,它里面有一个属性authenticationStrategy,并且
modularRealmAuthenticator在它的构造函数中将这个属性默认设置成new AtLeastOneSuccessfulStrategy():
private AuthenticationStrategy authenticationStrategy; /*-------------------------------------------- | C O N S T R U C T O R S | ============================================*/ /** * Default no-argument constructor which * {@link #setAuthenticationStrategy(AuthenticationStrategy) enables} an * {@link org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy} by default. */ public ModularRealmAuthenticator() { this.authenticationStrategy = new AtLeastOneSuccessfulStrategy(); }
所有我们要配置认证策略,只需要配置modularRealmAuthenticator类中的authenticationStrategy属性。下面是配置认证策略的过程:
[main] dataSource=com.mchange.v2.c3p0.ComboPooledDataSource dataSource.driverClass=com.mysql.jdbc.Driver dataSource.jdbcUrl=jdbc:mysql://localhost:3306/test dataSource.user=root dataSource.password=root myRealm=org.apache.shiro.realm.jdbc.JdbcRealm myRealm.dataSource=$dataSource dataSource1=com.mchange.v2.c3p0.ComboPooledDataSource dataSource1.driverClass=com.mysql.jdbc.Driver dataSource1.jdbcUrl=jdbc:mysql://localhost:3306/test1 dataSource1.user=root dataSource1.password=root myRealm1=org.apache.shiro.realm.jdbc.JdbcRealm myRealm1.dataSource=$dataSource1 #配置认证策略 authenticator=org.apache.shiro.authc.pam.ModularRealmAuthenticator authenticationStrategy=org.apache.shiro.authc.pam.FirstSuccessfulStrategy authenticator.authenticationStrategy=$authenticationStrategy securityManager.authenticator=$authenticator securityManager.realms=$myRealm,$myRealm1
在配置认证策略中,我将认证策略配成了FirstSuccessFulStrategy,然后将这个配置了新的认证策略的认证器赋予了SecurityManager中的authenticator属性从而完成了认证策略的配置。为了测试这几个策略的区别,我在shiro.ini文件中又创建了一个realm,并注入了一个新的数据源:
两个数据库中都有users的表,但是数据并不相同。下面开始认证编码,还是那一套流程:
package test_JdbcRealm; 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; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class TestAuthencationStrategy { private static final Logger logger = LoggerFactory.getLogger(TestAuthencationStrategy.class); public static void main(String[] args) { //1.创建securityManager工厂 Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini"); //2.获取securityManager实例 SecurityManager securityManager = factory.getInstance(); //3.将SecurityManager实例设置到SecurityUtils工具类中 SecurityUtils.setSecurityManager(securityManager); //4。创建Subject实例 Subject subject = SecurityUtils.getSubject(); //5.获取token,模拟用户登陆 UsernamePasswordToken token = new UsernamePasswordToken("wangwu", "456789"); try { //6.认证token subject.login(token); if(subject.isAuthenticated()) { logger.info("登陆成功"); } } catch (AuthenticationException e) { // TODO Auto-generated catch block e.printStackTrace(); logger.error("用户名或密码错误,登陆失败"); } } }
运行控制台输出如下:
2019-07-26 23:54:32,756 INFO [com.mchange.v2.log.MLog] - MLog clients using slf4j logging. 2019-07-26 23:54:33,216 INFO [com.mchange.v2.c3p0.C3P0Registry] - Initializing c3p0-0.9.5.2 [built 08-December-2015 22:06:04 -0800; debug? true; trace: 10] 2019-07-26 23:54:33,344 INFO [org.apache.shiro.config.IniSecurityManagerFactory] - Realms have been explicitly set on the SecurityManager instance - auto-setting of realms will not occur. 2019-07-26 23:54:33,373 INFO [com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource] - Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, contextClassLoaderSource -> caller, dataSourceName -> 2zm2h7a4d1dnn281ezvn|7e0ea639, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.jdbc.Driver, extensions -> {}, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, forceSynchronousCheckins -> false, forceUseNamedDriverClass -> false, identityToken -> 2zm2h7a4d1dnn281ezvn|7e0ea639, idleConnectionTestPeriod -> 0, initialPoolSize -> 3, jdbcUrl -> jdbc:mysql://localhost:3306/test, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 0, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 15, maxStatements -> 0, maxStatementsPerConnection -> 0, minPoolSize -> 3, numHelperThreads -> 3, preferredTestQuery -> null, privilegeSpawnedThreads -> false, properties -> {user=******, password=******}, propertyCycle -> 0, statementCacheNumDeferredCloseThreads -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, userOverrides -> {}, usesTraditionalReflectiveProxies -> false ] 2019-07-26 23:54:33,677 INFO [com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource] - Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, contextClassLoaderSource -> caller, dataSourceName -> 2zm2h7a4d1dnn281ezvn|6e1567f1, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.jdbc.Driver, extensions -> {}, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, forceSynchronousCheckins -> false, forceUseNamedDriverClass -> false, identityToken -> 2zm2h7a4d1dnn281ezvn|6e1567f1, idleConnectionTestPeriod -> 0, initialPoolSize -> 3, jdbcUrl -> jdbc:mysql://localhost:3306/test1, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 0, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 15, maxStatements -> 0, maxStatementsPerConnection -> 0, minPoolSize -> 3, numHelperThreads -> 3, preferredTestQuery -> null, privilegeSpawnedThreads -> false, properties -> {user=******, password=******}, propertyCycle -> 0, statementCacheNumDeferredCloseThreads -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, userOverrides -> {}, usesTraditionalReflectiveProxies -> false ] 2019-07-26 23:54:33,696 INFO [org.apache.shiro.session.mgt.AbstractValidatingSessionManager] - Enabling session validation scheduler... 2019-07-26 23:54:33,704 INFO [test_JdbcRealm.TestAuthencationStrategy] - 登陆成功
可以看到虽然test数据库中没有wangwu这个用户,但是test1数据库中有,所以myRealm1的认证过程是成功了的,而myRealm的认证过程毋庸置疑是失败了的,但是我们这里配的认证策略是FirstSuccessfulStrategy,所以只要有一个成功,就认证成功。
我们把认证策略改成AllSuccessfulStrategy再来测试一下上面的认证流程,发现控制台输出了如下内容:
2019-07-26 23:59:26,933 INFO [com.mchange.v2.log.MLog] - MLog clients using slf4j logging. 2019-07-26 23:59:27,323 INFO [com.mchange.v2.c3p0.C3P0Registry] - Initializing c3p0-0.9.5.2 [built 08-December-2015 22:06:04 -0800; debug? true; trace: 10] 2019-07-26 23:59:27,447 INFO [org.apache.shiro.config.IniSecurityManagerFactory] - Realms have been explicitly set on the SecurityManager instance - auto-setting of realms will not occur. 2019-07-26 23:59:27,476 INFO [com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource] - Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, contextClassLoaderSource -> caller, dataSourceName -> 2zm2h7a4d1jymk14v9ac3|7e0ea639, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.jdbc.Driver, extensions -> {}, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, forceSynchronousCheckins -> false, forceUseNamedDriverClass -> false, identityToken -> 2zm2h7a4d1jymk14v9ac3|7e0ea639, idleConnectionTestPeriod -> 0, initialPoolSize -> 3, jdbcUrl -> jdbc:mysql://localhost:3306/test, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 0, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 15, maxStatements -> 0, maxStatementsPerConnection -> 0, minPoolSize -> 3, numHelperThreads -> 3, preferredTestQuery -> null, privilegeSpawnedThreads -> false, properties -> {user=******, password=******}, propertyCycle -> 0, statementCacheNumDeferredCloseThreads -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, userOverrides -> {}, usesTraditionalReflectiveProxies -> false ] org.apache.shiro.authc.UnknownAccountException: No account found for user [wangwu] at org.apache.shiro.realm.jdbc.JdbcRealm.doGetAuthenticationInfo(JdbcRealm.java:244) 2019-07-26 23:59:27,761 ERROR [test_JdbcRealm.TestAuthencationStrategy] - 用户名或密码错误,登陆失败 at org.apache.shiro.realm.AuthenticatingRealm.getAuthenticationInfo(AuthenticatingRealm.java:571) at org.apache.shiro.authc.pam.ModularRealmAuthenticator.doMultiRealmAuthentication(ModularRealmAuthenticator.java:219) at org.apache.shiro.authc.pam.ModularRealmAuthenticator.doAuthenticate(ModularRealmAuthenticator.java:269) at org.apache.shiro.authc.AbstractAuthenticator.authenticate(AbstractAuthenticator.java:198) at org.apache.shiro.mgt.AuthenticatingSecurityManager.authenticate(AuthenticatingSecurityManager.java:106) at org.apache.shiro.mgt.DefaultSecurityManager.login(DefaultSecurityManager.java:275) at org.apache.shiro.subject.support.DelegatingSubject.login(DelegatingSubject.java:260) at test_JdbcRealm.TestAuthencationStrategy.main(TestAuthencationStrategy.java:30)
报了用户找不到的异常,因为在test数据库中我们并没有wangwu这个用户,所以myRealm认证是失败的,而我们配置了AllSuccessfulStrategy这个策略,只要有一个认证失败,那么最终就认证失败,因此这里输出了认证失败的提示语。
以上是我今天所看的shiro认证策略的内容和应用,如果有什么纠正和补充的请在评论区留言,谢谢!