shiro权限控制架构
shiro实现的认证
1、从类的继承关系可以看出自定义的Realm只需要实现AuthorizingRealm类即可。
Realm继承关系.png
2、只需要实现下列两个方法即可
doGetAuthorizationInfo 授权
doGetAuthenticationInfo 认证
shiro中的加密
-
md5加密一般用来加密和做校验和
- MD5算法不可逆,内容相同无论执行多少次MD5加密生成的结果始终一致。
例如:可以对文件进行文件加密,保证文件的内容不被篡改 - 网上常见的MD5解密,只是做了把简单的字符串进行穷举解密
- MD5加密完始终是一个16进制的32位长度字符串
- MD5算法不可逆,内容相同无论执行多少次MD5加密生成的结果始终一致。
Shiro中如何使用MD5加密认证
- 用户登录时的处理在Realm中添加秘钥认证器
//给安全管理器设置realm
CustomerMd5Realm customerMd5Realm=new CustomerMd5Realm();
//自定义MD5秘钥匹配器
HashedCredentialsMatcher hashedCredentialsMatcher=new HashedCredentialsMatcher();
hashedCredentialsMatcher.setHashAlgorithmName("md5");//设置使用什么方式进行加密
hashedCredentialsMatcher.setHashIterations(1024);//设置散列的次数
customerMd5Realm.setCredentialsMatcher(hashedCredentialsMatcher);
- 在Realm中进行进行处理
//ByteSource.Util.bytes("12121")是做加盐处理 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { String principal=(String)authenticationToken.getPrincipal(); if("user".equals(principal)){ return new SimpleAuthenticationInfo(principal,"3aa17c6555fb36a1e20783b8cdacbd8e", ByteSource.Util.bytes("12121"),this.getName()); } return null; }
Shiro中实现授权
-
授权的概念
- 授权,即访问控制,控制谁能访问哪些资源,主体进行身份认证后需要分配权限方可访问系统的资源,对于某些资源没有权限是没有权限访问的
- 授权可以简单的理解为Who对What进行How操作
- who:即主体Subject 主体需要访问系统中的资源。
- what:即资源Resource,如系统菜单、页面、按钮、类方法等信息。资源包括资源类型和资源实例。
- how:授权/许可,规定了主体对资源的操作许可,权限离开资源没有意义,如用户查询权限、用户添加权限、某个类方法的调用权限等,通过权限
可知主体对哪些资源有哪些操作许可
-
授权的方式
-
基于角色的访问控制
-
RBAC基于角色的访问控制(Role-Base Access Controll)是以角色为中心进行访问控制。
if(subject.hasRole("admin")){ //操作什么资源 }
-
-
- 基于资源的访问控制(Resource-Based Access Control)是以资源为中心进行访问控制。
```java
if(subject.isPermission("user:*:create")){
}
```
- 权限字符串
- 权限字符串的规则:资源标识符:操作:资源实例标识符,意思是对哪个资源的哪个实例具有什么操作,权限字符串也可以使用*通配符。
- 用户修改权限:user:create,或者user:create:*
- 用户修改实例001的权限:user:update:001
- 用户实例001的所有权限:user:*:001
- 权限字符串的规则:资源标识符:操作:资源实例标识符,意思是对哪个资源的哪个实例具有什么操作,权限字符串也可以使用*通配符。
shiro中授权编程的方式
-
编程方式
if(subject.hasRole("admin")){ }
-
注解方式
@RequiresRoles("admin") public void hello(){}
-
标签方式
jsp/GSP 标签在jsp页面通过相应的标签方式完成
开发授权
- realm中实现
shiro与springboot进行整合
实现的方式
springboot整合shiro需要通过Filter的方式对Url进行拦截处理
实现过程
pom文件引入包
org.apache.shiro
shiro-spring-boot-starter
1.5.3
org.springframework.boot
spring-boot-starter-data-jpa
mysql
mysql-connector-java
com.alibaba
druid
1.1.19
定义配置类ShiroConfig
在配置类中主要配置shiro的拦截器、shiro安全管理器、shiro访问数据库域、MD5加密
- 配置拦截器
/**
* 定义拦截器
* @param defaultWebSecurityManager
* @return
*/
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();
//给filter设置公共安全管理器
shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
//配置访问权限
HashMap map = new HashMap<>();
map.put("/user/login","anon");
map.put("/user/register","anon");
map.put("/user/logout","anon");
map.put("/register.jsp","anon");
map.put("/**","authc");
shiroFilterFactoryBean.setLoginUrl("/login.jsp");
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return shiroFilterFactoryBean;
}
- 注入安全管理器
//创建安全管理器
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(AuthorizingRealm realm){
DefaultWebSecurityManager defaultWebSecurityManager=new DefaultWebSecurityManager();
realm.setCredentialsMatcher(getCredentialsMatcher());
defaultWebSecurityManager.setRealm(realm);
return defaultWebSecurityManager;
}
- 创建自己的访问数据库域
public class CustomRealm extends AuthorizingRealm {
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
String username=(String)principalCollection.getPrimaryPrincipal();
if("liuxiaobin".equals(username)){
SimpleAuthorizationInfo simpleAuthorizationInfo=new SimpleAuthorizationInfo();
simpleAuthorizationInfo.addRole("product");
simpleAuthorizationInfo.addRole("log");
return simpleAuthorizationInfo;
}
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
String username=(String)authenticationToken.getPrincipal();
UserServiceImpl userService=(UserServiceImpl) SpringUtils.getBean("userService");
User user=userService.getUserByUsername(username);
SimpleAuthenticationInfo simpleAuthenticationInfo=null;
if(user!=null) {
simpleAuthenticationInfo= new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), ByteSource.Util.bytes(user.getSalt()),this.getName());
}
return simpleAuthenticationInfo;
}
}
- 注入MD5加密加盐和散列处理
@Bean
public CredentialsMatcher getCredentialsMatcher(){
//自定义MD5秘钥匹配器
HashedCredentialsMatcher hashedCredentialsMatcher=new HashedCredentialsMatcher();
hashedCredentialsMatcher.setHashAlgorithmName("md5");//设置使用什么方式进行加密
hashedCredentialsMatcher.setHashIterations(1024);//设置散列的次数
return hashedCredentialsMatcher;
}
-
其他额外配置
-
盐生成类
public static String getSalt(int n){ char[] charts="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890!@@##!^%%$%$%$%$%$%$%$%$%@#(**&&&".toCharArray(); StringBuilder sb=new StringBuilder(); for (int i = 0; i < n; i++) { char aChar=charts[new Random().nextInt(charts.length)]; sb.append(aChar); } return sb.toString(); }
-
获取Bean的工具类
@Component public class SpringUtils implements ApplicationContextAware { private static ApplicationContext context; @Override public void setApplicationContext(org.springframework.context.ApplicationContext applicationContext) throws BeansException { this.context=applicationContext; } public static Object getBean(String beanName){ return context.getBean(beanName); } }
-
## shiro 缓存
#### shiro整合ehcache
- 添加ehche依赖
```xml
org.apache.shiro
shiro-ehcache
1.5.3
-
配置realm中开启缓存
@Bean public AuthorizingRealm getAuthorizingRealm(){ CustomRealm customRealm = new CustomRealm(); customRealm.setCredentialsMatcher(redentialsMatcher());//设置认证秘钥md5+salt+散列 //开启缓存 customRealm.setCachingEnabled(true);//开启全局缓存 customRealm.setCacheManager(ehCacheManager()); customRealm.setAuthenticationCachingEnabled(true);//开启认证缓存 customRealm.setAuthenticationCacheName("AuthenticationCache");//设置认证缓存的名字 customRealm.setAuthorizationCachingEnabled(true);//开启授权缓存 customRealm.setAuthorizationCacheName("AuthorizationCache");//设置授权缓存的名字 customRealm.setCacheManager(new EhCacheManager());//设置缓存管理器 return customRealm; }
shiro整合redis
-
添加redis依赖
org.springframework.boot spring-boot-starter-data-redis
-
redis实现shiro中的CacheManager
package com.bidr.springbootshiro.shiro.cache; import org.apache.shiro.cache.Cache; import org.apache.shiro.cache.CacheException; import org.apache.shiro.cache.CacheManager; import org.springframework.data.redis.core.RedisTemplate; public class RedisCacheShiroManager implements CacheManager { private RedisTemplate redisTemplate; public RedisCacheShiroManager(RedisTemplate redisTemplate){ this.redisTemplate=redisTemplate; } @Override public
Cache getCache(String s) throws CacheException { return new ReidsCacheShiro (s,redisTemplate); } } -
设置redis的缓存
package com.bidr.springbootshiro.shiro.cache; import org.apache.shiro.cache.Cache; import org.apache.shiro.cache.CacheException; import org.springframework.data.redis.core.RedisTemplate; import java.util.Collection; import java.util.Set; public class ReidsCacheShiro
implements Cache { private RedisTemplate redisTemplate; private String name; public ReidsCacheShiro(String name,RedisTemplate redisTemplate) { this.redisTemplate = redisTemplate; this.name=name; } @Override public V get(K k) throws CacheException { System.out.println((V)redisTemplate.opsForValue().get(k.toString())); return (V)redisTemplate.opsForValue().get(k.toString()); } @Override public V put(K k, V v) throws CacheException { redisTemplate.opsForValue().set(k.toString(),v); return v; } @Override public V remove(K k) throws CacheException { return null; } @Override public void clear() throws CacheException { } @Override public int size() { return 0; } @Override public Set keys() { return null; } @Override public Collection values() { return null; } }
-
shiroConfig中设置redisCacheManager
@Bean public CacheManager redisCacheManager(){ return new RedisCacheShiroManager(redisTemplate); } /** * 自定义realm实现 * 1、设置MD5加密验证机制 * 2、开启realm缓存 * @return */ @Bean public AuthorizingRealm getAuthorizingRealm(){ CustomRealm customRealm = new CustomRealm(); customRealm.setCredentialsMatcher(redentialsMatcher());//设置认证秘钥md5+salt+散列 //开启缓存 customRealm.setCachingEnabled(true);//开启全局缓存 //customRealm.setCacheManager(ehCacheManager()); customRealm.setCacheManager(redisCacheManager()); customRealm.setAuthenticationCachingEnabled(true);//开启认证缓存 customRealm.setAuthenticationCacheName("AuthenticationCache");//设置认证缓存的名字 customRealm.setAuthorizationCachingEnabled(true);//开启授权缓存 customRealm.setAuthorizationCacheName("AuthorizationCache");//设置授权缓存的名字 customRealm.setCacheManager(new EhCacheManager());//设置缓存管理器 return customRealm; }