创建测试工程
加入shiro-core的jar包及其依赖包
与其它java开源框架类似,将shiro的jar包加入项目就可以使用shiro提供的功能了。shiro-core是核心包必须选用,还提供了与web整合的shiro-web、与spring整合的shiro-spring、与任务调度quartz整合的shiro-quartz等,下边是shiro各jar包的maven坐标。
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.3.2</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-web</artifactId> <version>1.3.2</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.3.2</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId> <version>1.3.2</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-quartz</artifactId> <version>1.3.2</version> </dependency> 也可以通过引入shiro-all包括shiro所有的包: <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-all</artifactId> <version>1.3.2</version> </dependency>
创建工程目录
shiro.ini
通过Shiro.ini配置文件初始化SecurityManager环境。
配置 eclipse支持ini文件编辑:
在eclipse配置后,在classpath创建shiro-realm.ini配置文件,为了方便测试将用户名和密码配置的shiro.ini配置文件中:
[users]
zhang=111111
认证代码
public class TestAhentication { @Test public void testLoginAndLogout() { // 构建SecurityManager工厂,IniSecurityManagerFactory可以从ini文件中初始化SecurityManager环境 Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro-realm.ini"); // 通过工厂创建SecurityManager SecurityManager securityManager = factory.getInstance(); // 将securityManager设置到运行环境中 SecurityUtils.setSecurityManager(securityManager); // 创建一个Subject实例,该实例认证要使用上边创建的securityManager进行 Subject subject = SecurityUtils.getSubject(); // AuthenticationToken arg0 UsernamePasswordToken token = new UsernamePasswordToken("zhang","111111"); try { subject.login(token); } catch (AuthenticationException e) { // TODO Auto-generated catch block e.printStackTrace(); } // 用户认证状态 boolean isAuthenticated = subject.isAuthenticated(); System.out.println("用户登录认证结果:"+isAuthenticated); //密码错误异常 org.apache.shiro.authc.IncorrectCredentialsException //账号错误异常 org.apache.shiro.authc.UnknownAccountException subject.logout(); System.out.println("用户退出认证结果"+subject.isAuthenticated()); } }
常见的异常
UnknownAccountException
账号不存在异常如下:
org.apache.shiro.authc.UnknownAccountException: Realm [org.apache.shiro.realm.text.IniRealm@7c75222b] was unable to find account data for the submitted AuthenticationToken [org.apache.shiro.authc.UsernamePasswordToken - zhang, rememberMe=false].
IncorrectCredentialsException
当输入密码错误会抛此异常,如下:
org.apache.shiro.authc.IncorrectCredentialsException: Submitted credentials for token [org.apache.shiro.authc.UsernamePasswordToken - zhang, rememberMe=false] did not match the expected credentials.
更多异常
认证执行流程
1、 创建token令牌,token中有用户提交的认证信息即账号和密码
2、 执行subject.login(token),提交给securityManager (安全管理器),安全管理器在通过Authenticator进行认证,
3、 Authenticator 安排ModularRealmAuthenticator调用realm从ini配置文件取用户真实的账号和密码,这里使用的是IniRealm(shiro自带)
4、 IniRealm先根据token中的账号去ini中找该账号,如果找不到则给ModularRealmAuthenticator返回null,如果找到则匹配密码,匹配密码成功则认证通过。
通过token获取user的过程
密码匹配的过程源码
自定义Realm实现通过数据库查询数据
上边的程序使用的是Shiro自带的IniRealm,IniRealm从ini配置文件中读取用户的信息,大部分情况下需要从系统的数据库中读取用户信息,所以需要自定义realm。
shiro提供的realm
最基础的是Realm接口,CachingRealm负责缓存处理,AuthenticationRealm负责认证,AuthorizingRealm负责授权,通常自定义的realm继承AuthorizingRealm。
创建自定义realm类
public class CustomRealm extends AuthorizingRealm
public class CustomRealm extends AuthorizingRealm{ public void setName() { super.setName("customRealm"); } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token){ //获取认证凭证 UsernamePasswordToken upToken = (UsernamePasswordToken) token; String username = upToken.getUsername(); if (username == null) { throw new AuthenticationException("账号为空"); } //进行数据库查询账号信息 //模拟数据库查询信息 if (!username.equals("zhangsan1")) { return null; } //用户存在 获取到数据库的密码 返回出去 //假设密码是1111 String password = "1111"; SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, password, getName()); return info; } @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { // TODO Auto-generated method stub return null; } }
shiro-customRealm.ini
[main] #自定义 realm customRealm=com.td.shiro.realm.CustomRealm #将realm设置到securityManager securityManager.realms=$customRealm
进行测试
@Test public void testLoginAndLogout1() { // 构建SecurityManager工厂,IniSecurityManagerFactory可以从ini文件中初始化SecurityManager环境 Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro-customRealm.ini"); // 通过工厂创建SecurityManager SecurityManager securityManager = factory.getInstance(); // 将securityManager设置到运行环境中 SecurityUtils.setSecurityManager(securityManager); // 创建一个Subject实例,该实例认证要使用上边创建的securityManager进行 Subject subject = SecurityUtils.getSubject(); // AuthenticationToken arg0 UsernamePasswordToken token = new UsernamePasswordToken("zhangsan","1111"); try { subject.login(token); } catch (AuthenticationException e) { e.printStackTrace(); } // 用户认证状态 boolean isAuthenticated = subject.isAuthenticated(); System.out.println("用户登录认证结果:"+isAuthenticated); //密码错误异常 org.apache.shiro.authc.IncorrectCredentialsException //账号错误异常 org.apache.shiro.authc.UnknownAccountException subject.logout(); System.out.println("用户退出认证结果"+subject.isAuthenticated()); }