授权
一,授权概念
授权,也叫访问控制,即在应用中控制谁能访问哪些资源(如访问页面/编辑数据/页面操作等)。在授权中需了解的几个关键对象:主体(Subject)、资源(Resource)、权限(Permission)、角色(Role)。
二,授权方式
Shiro支持三种方式的授权:
编程式:通过写if/else授权代码块完成:
- Subject subject = SecurityUtils.getSubject();
- if(subject.hasRole(“admin”)) {
- //有权限
- } else {
- //无权限
- }
注解式:通过在执行的Java方法上放置相应的注解完成:
没有权限将抛出相应的异常;
JSP/GSP标签:在JSP/GSP页面通过相应的标签完成:
三,授权
1、在ini配置文件配置用户拥有的角色和角色对应的权限(shiro-permission.ini)
#用户
[users]
#用户zhang的密码是111111,此用户具有role1和role2两个角色
zhangsan=123,role1,role2
wang=123,role2
lisi=123,role1,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
2,测试用例
// 角色授权,资源授权
@Test
public void TestAuthorization() {
// 创建securityManager工厂,通过ini配置文件创建securityManager工厂
Factory<SecurityManager> factory = new IniSecurityManagerFactory(
"classpath:shiro-permission.ini");
// 创建SecurityManager
SecurityManager securityManager = factory.getInstance();
// 将securityManager设置当前的运行环境中(单例模式)
SecurityUtils.setSecurityManager(securityManager);
// 从SecurityUtils里边创建一个subject
Subject subject = SecurityUtils.getSubject();
// 在认证提交前准备token(令牌)
// 这里的账号和密码 将来是由用户输入进去
UsernamePasswordToken token = new UsernamePasswordToken("lisi","123");
try {
// 执行认证提交
subject.login(token);
} catch (AuthenticationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 是否认证通过
boolean isAuthenticated = subject.isAuthenticated();
System.out.println("是否认证通过:" + isAuthenticated);
//基于角色的授权
//hasRole传入角色唯一标识
boolean hasRole=subject.hasRole("role1");
System.out.println("是否拥有该角色:"+hasRole);
//基于多个角色的判断
boolean hasRoles=subject.hasAllRoles(Arrays.asList("role1","role2","role3"));
System.out.println("是否拥有多个角色:"+hasRoles);
//使用check进行授权,若不通过抛出异常
subject.checkRoles("role4");
//基于资源的授权
boolean isPermitted=subject.isPermitted("user:create");
System.out.println("是否可以操作该资源:"+isPermitted);
//对多个资源权限进行判断
boolean isPermittedAll=subject.isPermittedAll("user:create:1","user:update:1");
System.out.println("对多个资源权限进行判断:"+isPermittedAll);
//使用check进行授权,若不通过抛出异常
subject.checkPermission("user:delete");
}
权限标识符号规则:资源:操作:实例(中间使用半角:分隔)
user:create:01 表示对用户资源的01实例进行create操作。
user:create:表示对用户资源进行create操作,相当于user:create:*,对所有用户资源实例进行create操作。
user:*:01 表示对用户资源实例01进行所有操作。
四,自定义realm进行授权
1)1、在ini配置文件配置用户拥有的角色和角色对应的权限(shiro-relam.ini)
#自定义 realm
customRealm=com.example.shiro.realm.CustomRealm
#将realm设置到securityManager,相当 于spring中注入
securityManager.realms=$customRealm
2)自定义的realm
package com.example.shiro.realm;
import java.util.ArrayList;
import java.util.List;
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;
public class CustomRealm extends AuthorizingRealm {
// 设置realm的名称
@Override
public void setName(String name) {
super.setName("customRealm");
}
// 用于认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException {
// token是用户输入的
// 第一步从token中取出身份信息
String userCode = (String) token.getPrincipal();
//String username = (String)token.getPrincipal(); //得到用户名
// String password = new String((char[])token.getCredentials()); //得到密码
// 第二步:根据用户输入的userCode从数据库查询
// ....
// 如果查询不到返回null
//数据库中用户账号是zhangsansan
/*if(!userCode.equals("zhangsansan")){//
return null;
}*/
// 模拟从数据库查询到密码
String password = "111111";
// 如果查询到返回认证信息AuthenticationInfo
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
userCode, password, this.getName());
return simpleAuthenticationInfo;
}
// 用于授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(
PrincipalCollection principals) {
String usercode=(String) principals.getPrimaryPrincipal();
//模拟从数据库中获取了数据
List<String> permission=new ArrayList<String>();
permission.add("user:add");//用户的创建
permission.add("user:update");//用户的修改
SimpleAuthorizationInfo simpleAuthorizationInfo=new SimpleAuthorizationInfo();
//将从数据库中查到的信息放入simpleAuthorizationInfo中
simpleAuthorizationInfo.addStringPermissions(permission);
return simpleAuthorizationInfo;
}
}
3)测试用例
// 自定义realm,资源授权测试
@Test
public void testCustomRealm() {
// 创建securityManager工厂,通过ini配置文件创建securityManager工厂
Factory<SecurityManager> factory = new IniSecurityManagerFactory(
"classpath:shiro-realm.ini");
// 创建SecurityManager
SecurityManager securityManager = factory.getInstance();
// 将securityManager设置当前的运行环境中
SecurityUtils.setSecurityManager(securityManager);
// 从SecurityUtils里边创建一个subject
Subject subject = SecurityUtils.getSubject();
// 在认证提交前准备token(令牌)
// 这里的账号和密码 将来是由用户输入进去
UsernamePasswordToken token = new UsernamePasswordToken("zhangsan",
"111111");
try {
// 执行认证提交
subject.login(token);
} catch (AuthenticationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 是否认证通过
boolean isAuthenticated = subject.isAuthenticated();
System.out.println("是否认证通过:" + isAuthenticated);
//基于角色的授权
//hasRole传入角色唯一标识
/*boolean hasRole=subject.hasRole("role1");
System.out.println("是否拥有该角色:"+hasRole);*/
//基于多个角色的判断
/*boolean hasRoles=subject.hasAllRoles(Arrays.asList("role1","role2","role3"));
System.out.println("是否拥有多个角色:"+hasRoles);*/
//使用check进行授权,若不通过抛出异常
// subject.checkRoles("role4");
//基于资源的授权
boolean isPermitted=subject.isPermitted("user:add");
System.out.println("是否可以操作该资源:"+isPermitted);
//对多个资源权限进行判断
boolean isPermittedAll=subject.isPermittedAll("user:create:1","user:update:1");
System.out.println("对多个资源权限进行判断:"+isPermittedAll);
//使用check进行授权,若不通过抛出异常
subject.checkPermission("user:delete");
}