Shiro授权
一、授权
授权
,即访问控制,控制谁能访问哪些资源。主体进行身份认证后需要分配权限方可访问系统的资源,对于某些资源没有权限是无法访问的。
二、关键对象
授权可简单理解为who对what(which)进行How操作:
Who,即主体(Subject)
,主体需要访问系统中的资源。
What,即资源(Resource)
,如系统菜单、页面、按钮、类方法、系统商品信息等。资源包括资源类型
和资源实例
,比如商品信息为资源类型
,类型为t01的商品为资源实例
,编号为001的商品信息也属于资源实例。
How,权限/许可(Permission)
,规定了主体对资源的操作许可,权限离开资源没有意义,如用户查询权限、用户添加权限、某个类方法的调用权限、编号为001用户的修改权限等,通过权限可知主体对哪些资源都有哪些操作许可。
三、授权流程
四、授权方式
-
基于角色的访问控制
-
RBAC基于角色的访问控制(Role-Based Access Control)是以角色为中心进行访问控制
if(subject.hasRole("admin")){ //操作什么资源 } 123
-
-
基于资源的访问控制
-
RBAC基于资源的访问控制(Resource-Based Access Control)是以资源为中心进行访问控制
if(subject.isPermission("user:update:01")){ //资源实例 //对01用户进行修改 } if(subject.isPermission("user:update:*")){ //资源类型 //对01用户进行修改 } 123456
-
五、权限字符串
权限字符串的规则是:资源标识符:操作:资源实例标识符,意思是对哪个资源的哪个实例具有什么操作,“:”是资源/操作/实例的分割符,权限字符串也可以使用*通配符。
例子:
- 用户创建权限:user:create,或user:create:*
- 用户修改实例001的权限:user:update:001
- 用户实例001的所有权限:user : * :001
A:B:C,A通过B来操作C
六、shiro中授权编程实现方式
-
编程式
Subject subject = SecurityUtils.getSubject(); if(subject.hasRole(“admin”)) { //有权限 } else { //无权限 } 123456
-
注解式
@RequiresRoles("admin") public void hello() { //有权限 } 1234
-
标签式
JSP/GSP 标签:在JSP/GSP 页面通过相应的标签完成: <shiro:hasRole name="admin"> <!— 有权限—> </shiro:hasRole> 注意: Thymeleaf 中使用shiro需要额外集成! 12345
七、开发授权
1.realm的实现
public class CustomMD5Realm extends AuthorizingRealm {
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("===================");
//获取主身份,也就是用户名
String primaryPrincipal = (String) principals.getPrimaryPrincipal();
System.out.println("身份信息:"+primaryPrincipal);
SimpleAuthorizationInfo simpleAuthenticationInfo = new SimpleAuthorizationInfo();
//添加角色
simpleAuthenticationInfo.addRole("admin");
simpleAuthenticationInfo.addStringPermission("user:update:*");
simpleAuthenticationInfo.addStringPermission("product:*:*");
return simpleAuthenticationInfo;
}
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String username = (String) token.getPrincipal();//用户名
if ("achang".equals(username)) {
//数据库中存的密码
String password = "a5adc0fc389b3236f04d1bf32e127440";//密码,123456的MD5加密
String salt = "k2*dw";//盐
//参数1:数据库用户名
//参数2:数据库密码,md5+salt的密码
//参数3:注册时的盐
//参数4:realm名
return new SimpleAuthenticationInfo(username,
password,
ByteSource.Util.bytes(salt),
this.getName());
}
return null;
}
}
2.授权
public class TestAuthenticatorCustomMD5Realm {
public static void main(String[] args) {
DefaultSecurityManager securityManager = new DefaultSecurityManager();
//设置自定义的MD5+盐+hash散列的Realm
CustomMD5Realm md5Realm = new CustomMD5Realm();
//设置自定义的realm使用hash凭证匹配器,来改变密码校验方式
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
hashedCredentialsMatcher.setHashAlgorithmName("MD5");//设置hash匹配器算法
hashedCredentialsMatcher.setHashIterations(1024);//设置散列次数
md5Realm.setCredentialsMatcher(hashedCredentialsMatcher);
securityManager.setRealm(md5Realm);
SecurityUtils.setSecurityManager(securityManager);
Subject subject = SecurityUtils.getSubject();
//创建token令牌
//用户登录使用明文密码访问
UsernamePasswordToken token = new UsernamePasswordToken("achang", "123456");
try {
subject.login(token);//用户登录
System.out.println("登录成功~~");
} catch (UnknownAccountException e) {
e.printStackTrace();
System.out.println("用户名错误!!");
}catch (IncorrectCredentialsException e){
e.printStackTrace();
System.out.println("密码错误!!!");
}
if(subject.isAuthenticated()){
//基于角色权限管理
boolean admin = subject.hasRole("admin");
System.out.println(admin);
//基于多角色权限控制,hasAllRoles只要有一个该subject不含有,就返回false
boolean roles = subject.hasAllRoles(Arrays.asList("admin","super"));
System.out.println(roles);
//是否具有其中一个角色,返回布尔数组,含有就是t,不含有就是f
boolean[] booleans = subject.hasRoles(Arrays.asList("admin","super","user"));
// 基于权限字符串的访问控制,资源标识符:操作:资源类型
boolean permitted = subject.isPermitted("product:create:001");
boolean user = subject.isPermitted("user:update");
System.out.println(permitted);
System.out.println(user);
//分别具有哪些权限
boolean[] permitted1 = subject.isPermitted("product:create:001", "user:update");
//同时具有哪些权限
boolean permittedAll = subject.isPermittedAll("product:create:001", "user:update");
}
}
}
整合SpringBoot项目实战
零、整合思路
一、创建springboot项目
二、引入shiro依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-starter</artifactId>
<version>1.5.3</version>
</dependency>
三、配置shiro环境
1.配置shiroFilterFactoryBean
@Configuration
public class ShiroConfig {
//1、shiroFilter
//负责拦截所有请求
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//注入安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
//设置受限资源
HashMap<String, String> map = new HashMap<>();
map.put("/index.jsp","authc");//authc 请求这个资源,需要认证授权
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
//默认认证界面路径
shiroFilterFactoryBean.setLoginUrl("/login.jsp");
return shiroFilterFactoryBean;
}
//2、安全管理器
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(Realm realm){
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
defaultWebSecurityManager.setRealm(realm);
return defaultWebSecurityManager;
}
//3、自定义Realm
@Bean
@Primary
public Realm getRealm(){
return new CustomRealm();
}
}
3.创建自定义realm
//自定义Realm
public class CustomRealm extends AuthorizingRealm {
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
return null;
}
}
4.编写控制器跳转至index.html
@Controller
public class IndexController {
@RequestMapping("index")
public String index(){
System.out.println("跳转至主页");
return "index";
}
}
5.启动springboot应用访问index
- 注意:
- 默认在配置好shiro环境后默认环境中没有对项目中任何资源进行权限控制,所有现在项目中所有资源都可以通过路径访问
6.加入权限控制
-
修改ShiroFilterFactoryBean配置
//设置受限资源 HashMap<String, String> map = new HashMap<>(); map.put("/index.jsp","authc");//authc 请求这个资源,需要认证授权 //map.put("/**","authc"); shiroFilterFactoryBean.setFilterChainDefinitionMap(map); //默认认证界面路径 shiroFilterFactoryBean.setLoginUrl("/login.jsp");
- /** 代表拦截项目中一切资源 authc 代表shiro中的一个filter的别名,详细内容看文档的shirofilter列表