开心一下:昨天晚上下班回家,一民警迎面巡逻而来。突然对我大喊:站住!
民警:java中int类型占几个字节?
我:4个。
民警:你可以走了。
我感到很诧异。
我:为什么问这样的问题?
民警:深夜还在街上走,寒酸苦逼的样子,不是小偷就是程序员。
继续学习开涛的Shiro身份验证,介绍一下开发工具和开发环境,jdk1.6.0_43+Tomcat6.0.29+ MyEclipse10.5,没有使用Maven。
Realm
Realm:域,Shiro从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;可以把Realm看成DataSource,即安全数据源。如我们之前的ini配置方式将使用org.apache.shiro.realm.text.IniRealm。新建web工程,工程名为ShrRealm,选择Java EE5.0
单Realm配置
一、 新建java类MyRealm1.java
package com.zsf.realms;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.realm.Realm;
public class MyRealm1 implements Realm {
public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token)
throws AuthenticationException {
System.out.println("MyRealm1~~~~~~~~~~~~~~~~~~~~~~~~~~");
//得到用户名
String username = (String) token.getPrincipal();
//得到密码
String password = new String((char[])token.getCredentials());
if(!"zhang".equals(username)) {
throw new UnknownAccountException();//用户名错误
}
if(!"1234".equals(password)) {
throw new IncorrectCredentialsException();//密码错误
}
//如果身份验证成功,返回一个AuthenticationInfo实现;
return new SimpleAuthenticationInfo(username, password, getName());
}
public String getName() {
return "MyRealm1";
}
public boolean supports(AuthenticationToken arg0) {
//仅支持UsernamePasswordToken类型的Token
return arg0 instanceof UsernamePasswordToken;
}
}
二、 在src下新建shiro-realm.in文件
#声明一个realm
myRealm1=com.zsf.realms.MyRealm1
#指定securityManager的realms实现
securityManager.realms=$myRealm1
三、 新建类RealmTest.java
package com.zsf.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;
/**
* 类名: RealmTest.java
* 作者: 张述飞
* 创建时间: 2016-2-25上午10:26:58
* 版本: V1.0
* 功能描述:
*/
public class RealmTest {
public static void main(String[] args) {
//获取SecurityManager工厂,此处使用Ini配置文件初始化SecurityManager
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro-realm.ini");
//得到SecurityManager实例,并绑定给SecurityUtils
SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
//得到Subject及创建用户名/密码身份验证Token(即用户身份/凭证)
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken("zhang", "1234");
try {
//登录,即身份验证
subject.login(token);
boolean flag = subject.isAuthenticated();
System.out.println("flag==="+flag);
System.out.println("登陆成功!");
} catch (AuthenticationException e) {
//身份验证失败
e.printStackTrace();
System.out.println("登陆失败!");
}
//6、退出
subject.logout();
}
}
四、 需导入的jar包
commons-beanutils-1.8.0.jar
commons-dbcp-1.2.1.jar
commons-logging-1.1.3.jar
commons-pool-1.3.jar
jtds-1.2.5.jar
shiro-core-1.2.4.jar
slf4j-api-1.7.9.jar
slf4j-jdk14-1.7.9.jar
五、 测试
运行RealmTest.java,
控制台会显示
MyRealm1~~~~~~~~~~~~~~~~~~~~~~~~~~
2016-2-25 10:29:04 org.apache.shiro.session.mgt.AbstractValidatingSessionManager enableSessionValidation
信息: Enabling session validation scheduler...
flag===true
登陆成功!
多Realm配置
六、 新建MyRealm2.java
package com.zsf.realms;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.realm.Realm;
public class MyRealm2 implements Realm {
public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token)
throws AuthenticationException {
System.out.println("MyRealm2~~~~~~~~~~~~~~~~~~~~~~~~~~");
//得到用户名
String username = (String) token.getPrincipal();
//得到密码
String password = new String((char[])token.getCredentials());
if(!"wang".equals(username)) {
throw new UnknownAccountException();//用户名错误
}
if(!"123".equals(password)) {
throw new IncorrectCredentialsException();//密码错误
}
//如果身份验证成功,返回一个AuthenticationInfo实现;
return new SimpleAuthenticationInfo(username, password, getName());
}
public String getName() {
return "MyRealm2";
}
public boolean supports(AuthenticationToken arg0) {
//仅支持UsernamePasswordToken类型的Token
return arg0 instanceof UsernamePasswordToken;
}
}
七、 新建shiro-multi-realm.ini
#声明一个realm
myRealm1=com.zsf.realms.MyRealm1
myRealm2=com.zsf.realms.MyRealm2
#指定securityManager的realms实现
securityManager.realms=$myRealm1,$myRealm2
八、 新建测试类MultiRealmTest.java
package com.zsf.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;
/**
* 类名: MultiRealmTest.java
* 作者: 张述飞
* 创建时间: 2016-2-25上午10:27:29
* 版本: V1.0
* 功能描述:
*/
public class MultiRealmTest {
public static void main(String[] args) {
//获取SecurityManager工厂,此处使用Ini配置文件初始化SecurityManager
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro-multi-realm.ini");
//得到SecurityManager实例,并绑定给SecurityUtils
SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
//得到Subject及创建用户名/密码身份验证Token(即用户身份/凭证)
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken("wang", "123");
try {
//登录,即身份验证
subject.login(token);
boolean flag = subject.isAuthenticated();
System.out.println("flag==="+flag);
System.out.println("登陆成功!");
} catch (AuthenticationException e) {
//身份验证失败
e.printStackTrace();
System.out.println("登陆失败!");
}
//6、退出
subject.logout();
}
}
九、 测试
运行MultiRealmTest.java,
控制台会显示
MyRealm1~~~~~~~~~~~~~~~~~~~~~~~~~~
MyRealm2~~~~~~~~~~~~~~~~~~~~~~~~~~
2016-2-25 10:37:56 org.apache.shiro.session.mgt.AbstractValidatingSessionManager enableSessionValidation
信息: Enabling session validation scheduler...
flag===true
登陆成功!
JDBC Realm使用
十、 新建MyRealm3.java
package com.zsf.realms;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.realm.Realm;
public class MyRealm3 implements Realm {
public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token)
throws AuthenticationException {
System.out.println("MyRealm3~~~~~~~~~~~~~~~~~~~~~~~~~~");
//得到用户名
String username = (String) token.getPrincipal();
//得到密码
String password = new String((char[])token.getCredentials());
if(!"zhang".equals(username)) {
throw new UnknownAccountException();//用户名错误
}
if(!"1234".equals(password)) {
throw new IncorrectCredentialsException();//密码错误
}
//如果身份验证成功,返回一个AuthenticationInfo实现;
return new SimpleAuthenticationInfo(username+"@163.com", password, getName());
}
public String getName() {
return "MyRealm3";
}
public boolean supports(AuthenticationToken arg0) {
//仅支持UsernamePasswordToken类型的Token
return arg0 instanceof UsernamePasswordToken;
}
}
十一、 新建shiro-jdbc-realm.ini
dataSource=org.apache.commons.dbcp.BasicDataSource
dataSource.driverClassName=net.sourceforge.jtds.jdbc.Driver
dataSource.url=jdbc:jtds:sqlserver://localhost:1433/TKERP
dataSource.username=sa
#dataSource.password=
jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
jdbcRealm.dataSource=$dataSource
jdbcRealm.permissionsLookupEnabled = true
jdbcRealm.authenticationQuery = select Password from UserInfo where LoginName=?
securityManager.realms=$jdbcRealm
十二、 解析一下上面的ini文件
#dataSource.password=这句话表示数据库sa密码为空,必须要这么写,否则会报错
Exception in thread "main" java.lang.IllegalArgumentException: Line argument must contain a key and a value. Only one string token was found.
at org.apache.shiro.config.Ini$Section.splitKeyValue(Ini.java:542)
at org.apache.shiro.config.Ini$Section.toMapProps(Ini.java:567)
at org.apache.shiro.config.Ini$Section.<init>(Ini.java:464)
at org.apache.shiro.config.Ini$Section.<init>(Ini.java:445)
at org.apache.shiro.config.Ini.addSection(Ini.java:302)
需要新建一个名为TKERP的数据库,还要新建一个表UserInfo,包括两个字段LoginName, Password,并且要填加一条记录,zsf,123
十三、 新建测试类JdbcRealmTest.java
package com.zsf.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;
/**
* 类名: JdbcRealmTest.java
* 作者: 张述飞
* 创建时间: 2016-2-25上午10:27:21
* 版本: V1.0
* 功能描述:
*/
public class JdbcRealmTest {
public static void main(String[] args) {
//获取SecurityManager工厂,此处使用Ini配置文件初始化SecurityManager
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro-jdbc-realm.ini");
//得到SecurityManager实例,并绑定给SecurityUtils
SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
//得到Subject及创建用户名/密码身份验证Token(即用户身份/凭证)
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken("zsf", "123");
try {
//登录,即身份验证
subject.login(token);
boolean flag = subject.isAuthenticated();
System.out.println("flag==="+flag);
System.out.println("登陆成功!");
} catch (AuthenticationException e) {
//身份验证失败
e.printStackTrace();
System.out.println("登陆失败!");
}
//6、退出
subject.logout();
}
}
十四、 测试
运行JdbcRealmTest.java,
控制台会显示
信息: Enabling session validation scheduler...
flag===true
登陆成功!
Authenticator及AuthenticationStrategy
Authenticator的职责是验证用户帐号,是Shiro API中身份验证核心的入口点:
SecurityManager接口继承了Authenticator,另外还有一个ModularRealmAuthenticator实现,其委托给多个Realm进行验证,验证规则通过AuthenticationStrategy接口指定,默认提供的实现:
FirstSuccessfulStrategy:只要有一个Realm验证成功即可,只返回第一个Realm身份验证成功的认证信息,其他的忽略;
AtLeastOneSuccessfulStrategy:只要有一个Realm验证成功即可,和FirstSuccessfulStrategy不同,返回所有Realm身份验证成功的认证信息;
AllSuccessfulStrategy:所有Realm验证成功才算成功,且返回所有Realm身份验证成功的认证信息,如果有一个失败就失败了。
ModularRealmAuthenticator默认使用AtLeastOneSuccessfulStrategy策略。
假设我们有三个realm:
myRealm1: 用户名/密码为zhang/1234时成功,且返回身份/凭据为zhang/1234;
myRealm2: 用户名/密码为wang/123时成功,且返回身份/凭据为wang/123;
myRealm3: 用户名/密码为zhang/1234时成功,且返回身份/凭据为zhang@163.com/1234,和myRealm1不同的是返回时的身份变了;
十五、 新建shiro-authenticator-all-success.ini
#指定securityManager的authenticator实现
authenticator=org.apache.shiro.authc.pam.ModularRealmAuthenticator
securityManager.authenticator=$authenticator
#指定securityManager.authenticator的authenticationStrategy实现
allSuccessfulStrategy=org.apache.shiro.authc.pam.AllSuccessfulStrategy
securityManager.authenticator.authenticationStrategy=$allSuccessfulStrategy
#声明一个realm
myRealm1=com.zsf.realms.MyRealm1
myRealm2=com.zsf.realms.MyRealm2
myRealm3=com.zsf.realms.MyRealm3
#指定securityManager的realms实现
securityManager.realms=$myRealm1,$myRealm3
十六、 新建shiro-authenticator-all-fail.ini
#指定securityManager的authenticator实现
authenticator=org.apache.shiro.authc.pam.ModularRealmAuthenticator
securityManager.authenticator=$authenticator
#指定securityManager.authenticator的authenticationStrategy实现
allSuccessfulStrategy=org.apache.shiro.authc.pam.AllSuccessfulStrategy
securityManager.authenticator.authenticationStrategy=$allSuccessfulStrategy
#声明一个realm
myRealm1=com.zsf.realms.MyRealm1
myRealm2=com.zsf.realms.MyRealm2
myRealm3=com.zsf.realms.MyRealm3
#指定securityManager的realms实现
securityManager.realms=$myRealm1,$myRealm2
十七、 新建测试类AuthenticatorTest.java
package com.zsf.test;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
/**
* 类名: AuthenticatorTest.java
* 作者: 张述飞
* 创建时间: 2016-2-25上午10:27:12
* 版本: V1.0
* 功能描述:
*/
public class AuthenticatorTest {
public void login(String configFile) {
//获取SecurityManager工厂,此处使用Ini配置文件初始化SecurityManager
Factory<SecurityManager> factory = new IniSecurityManagerFactory(configFile);
//得到SecurityManager实例,并绑定给SecurityUtils
SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
//得到Subject及创建用户名/密码身份验证Token(即用户身份/凭证)
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken("zhang", "1234");
//登录,即身份验证
subject.login(token);
}
public void testAllSucessfulStrategyWithSuccess(){
System.out.println("调用成功方法~~~~~~~");
login("classpath:shiro-authenticator-all-success.ini");
Subject subject = SecurityUtils.getSubject();
PrincipalCollection principalCollection = subject.getPrincipals();
System.out.println("成功的集合:==="+principalCollection.asList().size());
}
public void testAllSucessfulStrategyWithSuccess(){
System.out.println("调用成功方法~~~~~~~");
login("classpath:shiro-authenticator-all-success.ini");
Subject subject = SecurityUtils.getSubject();
PrincipalCollection principalCollection = subject.getPrincipals();
System.out.println("成功的集合:==="+principalCollection.asList().size());
subject.logout();
}
public void testAllSucessfulStrategyWithFail(){
System.out.println("调用失败方法~~~~~~~");
login("classpath:shiro-authenticator-all-fail.ini");
Subject subject = SecurityUtils.getSubject();
PrincipalCollection principalCollection = subject.getPrincipals();
System.out.println("失败的集合:==="+principalCollection.asList().size());
subject.logout();
}
}
十八、 测试
运行RealmTest.java,
控制台会显示
调用成功方法~~~~~~~
2016-2-25 13:47:31 org.apache.shiro.config.IniSecurityManagerFactory isAutoApplyRealms
信息: Realms have been explicitly set on the SecurityManager instance - auto-setting of realms will not occur.
MyRealm1~~~~~~~~~~~~~~~~~~~~~~~~~~
MyRealm3~~~~~~~~~~~~~~~~~~~~~~~~~~
2016-2-25 13:47:31 org.apache.shiro.session.mgt.AbstractValidatingSessionManager enableSessionValidation
信息: Enabling session validation scheduler...
2016-2-25 13:47:31 org.apache.shiro.config.IniSecurityManagerFactory isAutoApplyRealms
信息: Realms have been explicitly set on the SecurityManager instance - auto-setting of realms will not occur.
成功的集合:===2
调用失败方法~~~~~~~
MyRealm1~~~~~~~~~~~~~~~~~~~~~~~~~~
MyRealm3~~~~~~~~~~~~~~~~~~~~~~~~~~
失败的集合:===2
这一章写的很乱,做完实例后都是直接上手抄的大神开涛的,本来想把自己理解的好好写一下,因为要出差,所以匆匆忙忙的写完了,需要源码的下!
重要事情说三遍,大神开涛的,大神开涛的,开涛的!
代码下载地址:
http://download.csdn.net/detail/zhangshufei8001/9443253