一、前言
回忆过去,shiro的认证忘不了:
0:通过securityFactory建立securityManager,加入securityUtil加入环境
1、subject(主体)请求认证,调用login(token)
2、securityManager开始认证
3、securityManager通过ModularRealmAuthenticator进行认证
4、ModularRealmAuthenticator将token传统给realm,realm根据token从数据源(库)查询用户信息的身份和凭证(用户名与密码)。
5、realm查询不到返回空(用户不存在异常),如果凭证错误,返回凭证错误。否则返回正确的AuthenticationInfo(认证信息)
二、shrio权限授权
权限授权验证,一样是四个步骤,写ini文件-----加载ini----认证用户----权限验证,请注意任何认证之后才验证权限,是一般的思路不要忘记了。
2.1 编写ini文件
shiro-permission.ini
#用户 [users] #用户zhang的密码是123,此用户具有role1和role2两个角色 ycy=111,role1,role2 ycy2=111,role2 #权限 [roles] #角色role1对资源user拥有create、update权限 role1=user:create,user:update #角色role2对资源user拥有create、delete权限 role2=user:create,user:delete #角色role3对资源user拥有create权限 role3=user:create
解读: user:create为我们的权限标示,表达:资源 : 操作 : 实例。因为我们这里默认是有实例。其实应该是:user:create:* 当然也可以真的某一个实例:user:create:01
ycy=111,role1 逗号第一位为我们的凭证(密码),后面为角色。
2.2编写测试程序
编写权限认证不要忘记用户认证
程序里面只多了个permitted(权限)或者hasRole(角色),其他的与我们用户认证是一样的。
package com.ycy.test; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.config.IniSecurityManagerFactory; import org.apache.shiro.mgt.*; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.subject.Subject; import org.apache.shiro.util.Factory; import org.junit.Test; import java.util.ArrayList; import java.util.Arrays; /** * Created by Administrator on 2015/10/16 0016. * 权限授权 */ public class authorizationTest { @Test public void testAuthorization(){ //创建securityManager工厂 Factory<SecurityManager> securityManagerFactory=new IniSecurityManagerFactory("classpath:shiro-permission.ini"); //获取security SecurityManager securityManager=securityManagerFactory.getInstance(); //蒋securityManager加入运行坏境 SecurityUtils.setSecurityManager(securityManager); //建立subject Subject subject=SecurityUtils.getSubject(); //创建用户令牌 UsernamePasswordToken usernamePasswordToken=new UsernamePasswordToken("ycy","111"); //先认证 subject.login(usernamePasswordToken); System.out.println("用户时候通过认证:" + subject.isAuthenticated()); //再权限授权验证(单个) Boolean isPermittedOne= subject.isPermitted("user:create"); System.out.println("单个权限认证:"+isPermittedOne); //授权验证权限(多个) Boolean isPermittedAll=subject.isPermittedAll("user:create", "user:update"); System.out.println("多个权限认证:" + isPermittedOne); //另外也可以角色验证权限(不建议) Boolean ishasRole= subject.hasRole("role1"); Boolean ishasRoleAll= subject.hasAllRoles(Arrays.asList("role1","role2")); System.out.println("单个角色验证:"+ishasRole+"|多个角色验证"+ishasRoleAll); } }
三、shrio权限授权(自定义realm)
1、自定义realm
package com.ycy.realm; 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; import java.util.ArrayList; import java.util.List; /** * Created by Administrator on 2015/10/15 0015. * 自定义数据源 */ public class CustomRealm extends AuthorizingRealm{ //用户认证 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { //authenticationToken为用户输入信息 String userCode=(String)authenticationToken.getPrincipal(); //模拟数据库操作查询用户 if(!userCode.equals("ycy")){ return null; } //查询密码为111 String password="111"; SimpleAuthenticationInfo info=new SimpleAuthenticationInfo(userCode,password,"customRealm"); return info; } //用户授权 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { //获取身份信息Principal //这里的值跟我们用户认证的时候SimpleAuthenticationInfo一样 String usercode=(String)principalCollection.getPrimaryPrincipal(); //查询数据库。。。。 //模拟查询到数据 List<String> permission=new ArrayList<String>(); permission.add("user:create"); permission.add("items:add"); //.................. //查询全选数据,返回授权信息 SimpleAuthorizationInfo simpleAuthorizationInfo=new SimpleAuthorizationInfo(); //增加权限信息 simpleAuthorizationInfo.addStringPermissions(permission); return simpleAuthorizationInfo; } }
2、编写ini程序
#用户信息配置 [main] #自定义realm cutomRealm= com.ycy.realm.CustomRealm #自定义realm注入到securityManager中(标签语言) securityManager.realms=$cutomRealm
3、测试自定义授权
//自定义权限realm信息 //用户登录和退出(自定义realm) @Test public void testCustomRealm(){ //创建一个securityManager 通过ini文件创建 Factory<SecurityManager> securityManagerFactory=new IniSecurityManagerFactory("classpath:shrio-realm.ini"); // XMLSecurityManager //创建SecurityManager SecurityManager securityManager= securityManagerFactory.getInstance(); //将SecurityManager创建到生成环境中 SecurityUtils.setSecurityManager(securityManager); //从SecurityUtils 构建一个subject org.apache.shiro.subject.Subject subject=SecurityUtils.getSubject(); //认证提交认证token UsernamePasswordToken usernamePasswordToken=new UsernamePasswordToken("ycy","111"); //执行认证提交认证 try { subject.login(usernamePasswordToken); }catch(AuthenticationException ex){ ex.printStackTrace(); } System.out.println("是否通过认证:" + subject.isAuthenticated()); //授权。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。 //单个权限授权 boolean ispermitted=subject.isPermitted("user:create"); //多个权限授权 boolean ispermittedAll=subject.isPermittedAll("user:create","items:add"); System.out.println("单个授权:"+ispermitted+"|多个授权"+ispermittedAll); //退出 subject.logout(); }
四、授权流程总结
1、对subject进行授权,调用的方法ispermitted("permission");括号里面为权限串:user:create
2、securityManager执行授权,通过ModularRealmAuthorize执行授权
3、ModularRealmAuthorizer执行realm从数据源查询数据 (调用doGetAuthorizationInfo)
4、ModularRealmAuthorizer(授权器)调用PermissionResolve(权限解析器)进行全新串对比
5、对比之后,ispermitted中的permission串与realm查询的串对比,无权限则抛出异常。有权限则通过授权。
注意:这个授权器modularRealmAuthorize跟我们的ModularRealmAuthenticator很像,做的事情也是从realm查询对比,但是功能不一样的:
ModularRealmAuthorizer 返回:SimpleAuthenticationInfo 认证信息
ModularRealmAuthenticator返回:simpleAuthorizationInfo 权限信息