授权,也叫访问控制,即在应用中控制谁能访问哪些资源(如访问页面/编辑数据/页面操作
等)。在授权中需了解的几个关键对象:主体(Subject)、资源(Resource)、权限(Permission)、角色(Role)。
关键对象介绍
主体
主体,即访问应用的用户,在Shiro中使用Subject代表该用户。用户只有授权后才允许访问相应的资源。
资源
在应用中用户可以访问的任何东西,比如访问JSP 页面、查看/编辑某些数据、访问某个业务方法、打印文本等等都是资源。用户只要授权后才能访问。
权限
安全策略中的原子授权单位,通过权限我们可以表示在应用中用户有没有操作某个资源的
权力。即权限表示在应用中用户能不能访问某个资源,如:访问用户列表页面查看/新增/修改/删除用户数据(即很多时候都是CRUD(增查改删)式权限控制)打印文档等等。。。
角色
角色代表了操作集合,可以理解为权限的集合,一般情况下我们会赋予用户角色而不是权
限,即这样用户可以拥有一组权限,赋予权限时比较方便。典型的如:项目经理、技术总监、CTO、开发工程师等都是角色,不同的角色拥有一组不同的权限。
授权流程
流程如下:
1、首先调用Subject.isPermitted*/hasRole接口,其会委托给SecurityManager,而SecurityManager接着会委托给Authorizer;
2、Authorizer是真正的授权者,如果我们调用如isPermitted(“user:view”),其首先会通过PermissionResolver把字符串转换成相应的Permission实例;
3、在进行授权之前,其会调用相应的Realm获取Subject相应的角色/权限用于匹配传入的角色/权限;
4、Authorizer会判断Realm的角色/权限是否和传入的匹配,如果有多个Realm,会委托给ModularRealmAuthorizer 进行循环判断,如果匹配如isPermitted/hasRole*会返回true,否则返回false表示授权失败。
授权方式
Shiro 支持三种方式的授权
//编程式:通过写if/else 授权代码块完成:
Subject subject = SecurityUtils.getSubject();
if(subject.hasRole(“admin”)) {
//有权限
} else {
//无权限
}
//注解式:通过在执行的Java方法上放置相应的注解完成:
//没有权限将抛出相应的异常;
@RequiresRoles("admin")
public void hello() {
//有权限
}
JSP/GSP 标签:在JSP/GSP 页面通过相应的标签完成:
<shiro:hasRole name="admin">
<!— 有权限—>
</shiro:hasRole>
授权实现
在ini配置文件配置用户拥有的角色及角色-权限关系
[users]
root=123,role1,role2
[roles]
role1 = user:add,user:delete
role2 = user:list
规则:“用户名=密码,角色1,角色2” “角色=权限1,权限2”,即首先根据用户名找到角色,然后根据角色再找到权限;即角色是权限集合;Shiro 同样不进行权限的维护,需要我们通过Realm返回相应的权限信息。只需要维护“用户——角色”之间的关系即可。
public static void main(String[] args) {
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro03");
SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken("root","123");
try {
subject.login(token);
System.out.println("成功登陆");
} catch (Exception e) {
System.out.println("登陆失败");
}
//检测是否拥有role1角色
if(subject.hasRole("role1")){
System.out.println("拥有role1的角色");
}
//基于资源的授权
if(subject.isPermitted("user:add")){
System.out.println("拥有user:add的权限");
}
//判断用户是否拥有权限,如果没有抛出异常
subject.checkPermission("user:list");
}
自定义Realm实现授权
public class UserRealm3 extends AuthorizingRealm {
/**
* @Description:授权信息
* @param principals
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(
PrincipalCollection principals) {
//获取用户名
String username = principals.getPrimaryPrincipal().toString();
//根据用户名查询权限信息
List<String> permission = new ArrayList<String>();
System.out.println("获取权限");
//模拟从数据库获取权限
permission.add("user:add");
permission.add("user:delete");
//将权限封装到SimpleAuthorizationInfo中
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addStringPermissions(permission);
return info;
}
/**
* @Description:身份认证
* @param token
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException {
//获取用户输入的用户名
String username = (String) token.getPrincipal();
System.out.println("验证用户信息");
//从数据库获取密码
String password = "123";
//将用户信息封装到SimpleAuthenticationInfo
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, password, getName());
return info;
}
}
[main]
userRealm = com.QEcode.realm.UserRealm3
securityManager.realm=$userRealm
[users]
root=123
public static void main(String[] args) {
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro04.ini");
SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken("root","123");
try {
subject.login(token);
if(subject.isAuthenticated()){
System.out.println("验证通过");
}
} catch (AuthenticationException e) {
e.printStackTrace();
System.out.println("验证失败");
}
//验证是否拥有权限
System.out.println(subject.isPermittedAll("user:add","user:delete"));
}