一、ini配置文件讲解
ini 配置文件类似于 Java 中的 properties(key=value),不过提供了将 key/value 分类的特性,key 是每个部分不重复即可,而不是整个配置文件。
- 使用Shiro 框架来完成认证工作默认情况下是使用iniRealm。如果需要其他Realm,那么需要进行相关配置。
- Ini配置文件讲解
[main] Section 是配置SecurityManager实例及其他任何依赖组件(如:Realm)的地方。
[main] MyRealm=com.study.Realm.MyRealm #依赖注入 SecurityManager..realm=$MyRealm |
[users]section 允许你定义一组静态的用户账户。
[users] zhansan=123,role1,role2 Lisi=123 |
[roles]section 允许你把定义在[users]section中的角色与账户权限关联起来。
[roles] Role1=zhansan:add,user2:detele |
二、使用单JdbcRealm来完成身份验证。
1、使用idea创建由Maven管理的Java工程。
2、在POM依赖文件中加入依赖。
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.9</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<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>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.32</version>
</dependency>
</dependencies>
此处因为我们需要访问数据库查询数据,所以要加入mysql驱动和连接池依赖。
3、加入Log4.properties日志文件
log4j.rootLogger=INFO,CONSOLE,A
log4j.addivity.org.apache=false
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Threshold=INFO
log4j.appender.CONSOLE.layout.ConversionPattern=%d{yyyy-MM-dd HH\:mm\:ss} -%-4r [%t] %-5p %x - %m%n
log4j.appender.CONSOLE.Target=System.out
log4j.appender.CONSOLE.Encoding=UTF-8
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.A=org.apache.log4j.DailyRollingFileAppender
log4j.appender.A.File=${catalina.home}/logs/qdexam_log/qdexam_
log4j.appender.A.DatePattern=yyyy-MM-dd'.log'
log4j.appender.A.layout=org.apache.log4j.PatternLayout
log4j.appender.A.layout.ConversionPattern=[qdexam_sys_log] %d{yyyy-MM-dd HH\:mm\:ss} %5p %c{1}\:%L \: %m%n
4、观察JdbcRealm
public class JdbcRealm extends AuthorizingRealm {
protected static final String DEFAULT_AUTHENTICATION_QUERY = "select password from users where username = ?";
protected static final String DEFAULT_SALTED_AUTHENTICATION_QUERY = "select password, password_salt from users where username = ?";
protected static final String DEFAULT_USER_ROLES_QUERY = "select role_name from user_roles where username = ?";
protected static final String DEFAULT_PERMISSIONS_QUERY = "select permission from roles_permissions where role_name = ?";
private static final Logger log = LoggerFactory.getLogger(JdbcRealm.class);
protected DataSource dataSource;
protected String authenticationQuery = "select password from users where username = ?";
protected String userRolesQuery = "select role_name from user_roles where username = ?";
protected String permissionsQuery = "select permission from roles_permissions where role_name = ?";
protected boolean permissionsLookupEnabled = false;
protected JdbcRealm.SaltStyle saltStyle;
我们发现Shiro为我们定义了许多SQL查询语句。所以我们应该创建此类的对象,并按照SQL语句中的数据表名和字段名创建数据库表。
其中password_salt为加密盐,后面篇文章会讲解。
5、编写测试代码,配置ini文件
1、首先看一下整个工程的目录结构。
2、编写代码
package com.study.shiro;
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;
/**
* @author James
* @create 2019-10-27 22:03
*
*
*/
public class JdbcRealmDemo {
public static void main(String[] args){
Factory<SecurityManager> factory=new IniSecurityManagerFactory("classpath:shiro.ini");
SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token=new UsernamePasswordToken("wangwu","1111");
try {
subject.login(token);
if (subject.isAuthenticated()){
System.out.println("验证通过...");
}
} catch (AuthenticationException e) {
System.out.println("验证失败...");
}
}
}
3、配置ini文件
3.1为JdbcRealm设置dataSource。
[main]
#配置数据源
dataSource=com.mchange.v2.c3p0.ComboPooledDataSource
dataSource.driverClass=com.mysql.jdbc.Driver
dataSource.jdbcUrl=jdbc:mysql://localhost:3306/sxt_shiro
dataSource.user=root
dataSource.password=123456
#配置Realm对象
jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
# $表示引用/注入对象
#为jdbcRealm注入dataSource
jdbcRealm.dataSource=$dataSource
#为securityManager注入realm
securityManager.realm=$jdbcRealm
测试代码中 我们的用户名/密码是wangwu,1111,数据库中有此用户,断言会验证通过。
此时我将密码改为:1234,再进行认证。
UsernamePasswordToken token=new UsernamePasswordToken("wangwu","1234");
"C:\Program Files\Java\jdk1.8.0_191\bin\java.exe" "-javaagent:D:\idea\IntelliJ IDEA 2018.3.1\lib\idea_rt.jar=56015:D:\idea\IntelliJ IDEA 2018.3.1\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_191\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\rt.jar;D:\idea_workspace\sxt\shiro\shiro02_shior_JdbcRealm\target\classes;D:\Maven-3.5.2\LocalRespMaven\maven_repository\junit\junit\4.9\junit-4.9.jar;D:\Maven-3.5.2\LocalRespMaven\maven_repository\org\hamcrest\hamcrest-core\1.1\hamcrest-core-1.1.jar;D:\Maven-3.5.2\LocalRespMaven\maven_repository\org\slf4j\slf4j-log4j12\1.7.21\slf4j-log4j12-1.7.21.jar;D:\Maven-3.5.2\LocalRespMaven\maven_repository\org\slf4j\slf4j-api\1.7.21\slf4j-api-1.7.21.jar;D:\Maven-3.5.2\LocalRespMaven\maven_repository\log4j\log4j\1.2.17\log4j-1.2.17.jar;D:\Maven-3.5.2\LocalRespMaven\maven_repository\org\apache\shiro\shiro-core\1.4.0\shiro-core-1.4.0.jar;D:\Maven-3.5.2\LocalRespMaven\maven_repository\org\apache\shiro\shiro-lang\1.4.0\shiro-lang-1.4.0.jar;D:\Maven-3.5.2\LocalRespMaven\maven_repository\org\apache\shiro\shiro-cache\1.4.0\shiro-cache-1.4.0.jar;D:\Maven-3.5.2\LocalRespMaven\maven_repository\org\apache\shiro\shiro-crypto-hash\1.4.0\shiro-crypto-hash-1.4.0.jar;D:\Maven-3.5.2\LocalRespMaven\maven_repository\org\apache\shiro\shiro-crypto-core\1.4.0\shiro-crypto-core-1.4.0.jar;D:\Maven-3.5.2\LocalRespMaven\maven_repository\org\apache\shiro\shiro-crypto-cipher\1.4.0\shiro-crypto-cipher-1.4.0.jar;D:\Maven-3.5.2\LocalRespMaven\maven_repository\org\apache\shiro\shiro-config-core\1.4.0\shiro-config-core-1.4.0.jar;D:\Maven-3.5.2\LocalRespMaven\maven_repository\org\apache\shiro\shiro-config-ogdl\1.4.0\shiro-config-ogdl-1.4.0.jar;D:\Maven-3.5.2\LocalRespMaven\maven_repository\commons-beanutils\commons-beanutils\1.9.3\commons-beanutils-1.9.3.jar;D:\Maven-3.5.2\LocalRespMaven\maven_repository\commons-collections\commons-collections\3.2.2\commons-collections-3.2.2.jar;D:\Maven-3.5.2\LocalRespMaven\maven_repository\org\apache\shiro\shiro-event\1.4.0\shiro-event-1.4.0.jar;D:\Maven-3.5.2\LocalRespMaven\maven_repository\commons-logging\commons-logging\1.2\commons-logging-1.2.jar;D:\Maven-3.5.2\LocalRespMaven\maven_repository\c3p0\c3p0\0.9.1.2\c3p0-0.9.1.2.jar;D:\Maven-3.5.2\LocalRespMaven\maven_repository\mysql\mysql-connector-java\5.1.32\mysql-connector-java-5.1.32.jar" com.study.shiro.JdbcRealmDemo
2019-11-05 23:29:54 -15 [main] INFO - MLog clients using log4j logging.
2019-11-05 23:29:54 -200 [main] INFO - Initializing c3p0-0.9.1.2 [built 21-May-2007 15:04:56; debug? true; trace: 10]
2019-11-05 23:29:54 -316 [main] INFO - Realms have been explicitly set on the SecurityManager instance - auto-setting of realms will not occur.
2019-11-05 23:29:54 -363 [main] INFO - 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, dataSourceName -> 1b61bmla6gp6qxi1f6t08z|38082d64, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.jdbc.Driver, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, identityToken -> 1b61bmla6gp6qxi1f6t08z|38082d64, idleConnectionTestPeriod -> 0, initialPoolSize -> 3, jdbcUrl -> jdbc:mysql://localhost:3306/sxt_shiro, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 0, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 15, maxStatements -> 0, maxStatementsPerConnection -> 0, minPoolSize -> 3, numHelperThreads -> 3, numThreadsAwaitingCheckoutDefaultUser -> 0, preferredTestQuery -> null, properties -> {user=******, password=******}, propertyCycle -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, usesTraditionalReflectiveProxies -> false ]
验证失败...
三、多Realm进行认证。
使用多Realm,就可以看做多个数据库(多个dataSource)。所以我们只需在ini文件中配置多个dataSource就行。
1、在这里我新建了一个数据库shiro1,数据表的字段还是和第一个数据库中的users表字段一模一样,只是新增了lisi这个用户。
2、在ini文件中增加dataSource2。指向数据库shiro1。
[main]
#配置数据源
dataSource=com.mchange.v2.c3p0.ComboPooledDataSource
dataSource.driverClass=com.mysql.jdbc.Driver
dataSource.jdbcUrl=jdbc:mysql://localhost:3306/sxt_shiro
dataSource.user=root
dataSource.password=123456
jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
# $表示引用对象
jdbcRealm.dataSource=$dataSource
#配置数据源2
dataSource2=com.mchange.v2.c3p0.ComboPooledDataSource
dataSource2.driverClass=com.mysql.jdbc.Driver
dataSource2.jdbcUrl=jdbc:mysql://localhost:3306/sxt_shiro1
dataSource2.user=root
dataSource2.password=123456
jdbcRealm2=org.apache.shiro.realm.jdbc.JdbcRealm
jdbcRealm2.dataSource=$dataSource2
securityManager.realms=$jdbcRealm,$jdbcRealm2
#配置策略
#AllSuccessfulStrategy:所有Realm验证成功才算成功,且返回所有Realm身份认证成功的认证信息,如果有一个失败就失败了
#配置验证器
authenticationStrategy=org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy
securityManager.authenticator.authenticationStrategy=$authenticationStrategy
3、多Realm认证就涉及到了验证策略。
Authenticating Strategy 认证策略
认证策略实际上是AuthenticationStrategy这个接口,它有三个实现:
(1)FirstSuccessfulStrategy:只要有一个Realm验证成功即可,只返回第一个Realm身份验证成功的认证信息,其他的忽略。
(2)AtLeatOneSuccessfulStrategy:只要有一个Realm验证成功即可,和FirstSuccessfulStrategy不同,AtLeatOneSuccessfulStrategy将返回所有Realm身份校验成功的认证信息。
(3)AllSuccessfulStrategy:所有Realm验证成功才算成功,且返回所有Realm身份认证成功的认证信息,如果有一个失败就失败了。
我们之前使用的ModularRealmAuthenticator默认是AtLeatOneSuccessfulStrategy。
1、 在这里我们使用AtLeatOneSuccessfulStrategy: lisi 用户 就能认证成功。
2、在这里我们使用AllSuccessfulStrategy:lisi 就会失败。
至此 我们的JdbcRealm,和验证策略就到此结束了。