shiro权限的认证及shiro的配置
一.使用shiro框架需要引入的依赖
<!--引入shiro的依赖-->
<!-- shiro start -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.3.2</version>
</dependency>
<!--日志包--> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.6.6</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.6.6</version> </dependency>
2.配置ini文件(代替数据库)
ini文件确定了数据库的认证规则
# 配置自定义的realm(自定义数据库认证规则)
[main]
# 配置加密认证的凭证匹配器
credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
credentialsMatcher.hashAlgorithmName=MD5
credentialsMatcher.hashIterations=2
myRealm=com.woniu.shiro.realm.md5.authorization.AuthenticationAuthorizationMD5Realm
myRealm.credentialsMatcher=$credentialsMatcher
securityManager.realms=$myRealm
3.配置Realm的Java代码
package com.woniu.shiro.realm.authorization; import java.util.HashSet; import java.util.Set; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; /** * 自定义认证、授权规则 【数据库校验】 */ @SuppressWarnings("all") public class AuthenticationAuthorizationRealm extends AuthorizingRealm{ //1. 认证规则 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { //1. principal 身份信息【账号, 用户对象】 Object principal = token.getPrincipal(); //2. 真实开发要使用这个身份去数据库查询该账号是否存在 if (!"admin".equals(principal)) // 模拟数据库只有一个admin账号 return null; //自动被UnknownAccountException捕获【账号不存在】 //3.credentials 真实数据库凭证 【就是账号对应的数据库密码】 Object credentials = "123"; //14. 构建一个 AuthenticationInfo 认证信息对象 SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(principal, credentials, getName()); /** * 将真实凭证credentials 与 token中的password进行equals()比较: * 相同 : 就返回authenticationInfo * 不相同: 抛出IncorrectCredentialsException [密码错误] */ return authenticationInfo; } //2. 授权规则(最终授予的是角色对应的权限) @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { //1. 需要获取到认证成功的身份 Object principal = principals.getPrimaryPrincipal(); //2. 查询权限 ;[开发中应该 : principal去查此身份对应的角色,通过角色再查询角色对应的权限【返回的是该身份所对应的权限集合】] Set<String> permissions = new HashSet<String>(); // 模拟一个数据库的权限查询结果 permissions.add("user:*"); permissions.add("item:select"); permissions.add("item:update"); permissions.add("item:insert"); //3. 构建一个 AuthorizationInfo 授权信息对象 SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); authorizationInfo.setStringPermissions(permissions); // 授权 return authorizationInfo; } }
Realm的工作原理:
1.根据subject.login(token)可以将token传到myrealm的认证方法里
2.从token中得到用户传来的用户账号和密码
3.根据用户的账号从数据库查找该用户,不存在则返回null
4.若用户存在则需要得到用户的密码,构建一个认证信息的对象 authenticationInfo = new SimpleAuthenticationInfo(待认证对象,数据库的密码,当前realm对象)
5.将数据库的密码与token中的密码进行equals判断,相同则return authenticationInfo 不同则 throw new IncorrectCredentialsException()
4.测试代码
package com.woniu.shiro.realm.authorization; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.config.IniSecurityManagerFactory; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.subject.Subject; /** * 通过读取配置文件info.ini来完成shior认证 * SecurityManager: 管理认证和授权 * * 【 认证 】: 将subject用户校验【前端form】的账号、密码与info.ini配置文件中的账号/密码进行比对 */ @SuppressWarnings("all") public class ShiroAuthenticationAuthorizationTest { public static void main(String[] args) { //1. 创建Shiro安全管理工厂 IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:info_realm_authorization.ini"); //2. 从工厂中创建出SecurityManager安全管理对象 SecurityManager securityManager = factory.getInstance(); //3. 将安全管理对象与shior环境绑定 SecurityUtils.setSecurityManager(securityManager); //4. 创建待校验的subject(用户) Subject subject = SecurityUtils.getSubject(); //5.创建账号密码令牌 【token : 令牌】 UsernamePasswordToken token = new UsernamePasswordToken("admin", "123"); //6.开始认证 try { subject.login(token); // 登录验证 }catch (UnknownAccountException e) { // UnknownAccountException 未知的账号异常 System.out.println("用户名不存在"); }catch (IncorrectCredentialsException e) { // IncorrectCredentialsException 不正确的凭证异常 System.out.println("密码错误"); }catch (AuthenticationException e) { // AuthenticationException 认证异常 System.out.println("未知错误"); } //7.认证是否通过的判断条件 System.out.println("认证的结果 : " + subject.isAuthenticated()); if(!subject.isAuthenticated()) return; //8.判断此身份具有哪些体统操作的权限 System.out.println("用户添加权限:"+subject.isPermitted("user:insert")); System.out.println("用户删除权限:"+subject.isPermitted("user:delete")); System.out.println("用户修改权限:"+subject.isPermitted("user:update")); System.out.println("用户查询权限:"+subject.isPermitted("user:select")); System.out.println("-----------------------------------------"); System.out.println("商品添加权限:"+subject.isPermitted("item:insert")); System.out.println("商品删除权限:"+subject.isPermitted("item:delete")); System.out.println("商品修改权限:"+subject.isPermitted("item:update")); System.out.println("商品查询权限:"+subject.isPermitted("item:select")); } }
shiro底层执行流程
1.利用IniSecurityManagerFactory加载配置文件并创建工厂(factory) =>
2.利用工厂创建安全管理对象(securityManager=factory.getInstance()) =>
3.将安全管理对象与shiro环境绑定SecurityUtils.setSecurityManager(securityManager)=>
4.创建待校验的subject(用户) =>
5. 创建账号的密码令牌new UsernamePasswordToken("前端账号","前端密码") =>
6.进行校验subject.login(token);
shiro的认证流程
首先根据配置文件创建安全管理工厂factor =new iniSecurityManagerFactory("classpath:配置文件名称") ==>
再通过工厂创建安全管理对象manager = factory.getInstance() ==>
之后将对象与shiro绑定 SecurityUtils.setSecurityManager(securityManager) ==>
得到subject对象SecurityUtils.getSubject()==>
创建用户token = new UsernamePasswordToken("用户账号","用户密码") ==>
subject.login(token)==>
会将token'传给realm,在realm中得到token并将token中的账号取出来 ==>
通过账号从数据库查询user,用数据库查询出来的user的密码与token中的密码比对 ==>
根据结果返回相应的行为;