shiro權(quán)限控制架構(gòu)
shiro實(shí)現(xiàn)的認(rèn)證
1表锻、從類的繼承關(guān)系可以看出自定義的Realm只需要實(shí)現(xiàn)AuthorizingRealm類即可胀滚。
Realm繼承關(guān)系.png
2炼绘、只需要實(shí)現(xiàn)下列兩個(gè)方法即可
doGetAuthorizationInfo 授權(quán)
doGetAuthenticationInfo 認(rèn)證
shiro中的加密
-
md5加密一般用來加密和做校驗(yàn)和
- MD5算法不可逆替蛉,內(nèi)容相同無論執(zhí)行多少次MD5加密生成的結(jié)果始終一致吃警。
例如:可以對文件進(jìn)行文件加密,保證文件的內(nèi)容不被篡改 - 網(wǎng)上常見的MD5解密阀蒂,只是做了把簡單的字符串進(jìn)行窮舉解密
- MD5加密完始終是一個(gè)16進(jìn)制的32位長度字符串
- MD5算法不可逆替蛉,內(nèi)容相同無論執(zhí)行多少次MD5加密生成的結(jié)果始終一致吃警。
Shiro中如何使用MD5加密認(rèn)證
- 用戶登錄時(shí)的處理在Realm中添加秘鑰認(rèn)證器
//給安全管理器設(shè)置realm
CustomerMd5Realm customerMd5Realm=new CustomerMd5Realm();
//自定義MD5秘鑰匹配器
HashedCredentialsMatcher hashedCredentialsMatcher=new HashedCredentialsMatcher();
hashedCredentialsMatcher.setHashAlgorithmName("md5");//設(shè)置使用什么方式進(jìn)行加密
hashedCredentialsMatcher.setHashIterations(1024);//設(shè)置散列的次數(shù)
customerMd5Realm.setCredentialsMatcher(hashedCredentialsMatcher);
- 在Realm中進(jìn)行進(jìn)行處理
//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中實(shí)現(xiàn)授權(quán)
-
授權(quán)的概念
- 授權(quán)该窗,即訪問控制,控制誰能訪問哪些資源蚤霞,主體進(jìn)行身份認(rèn)證后需要分配權(quán)限方可訪問系統(tǒng)的資源酗失,對于某些資源沒有權(quán)限是沒有權(quán)限訪問的
- 授權(quán)可以簡單的理解為Who對What進(jìn)行How操作
- who:即主體Subject 主體需要訪問系統(tǒng)中的資源。
- what:即資源Resource昧绣,如系統(tǒng)菜單规肴、頁面、按鈕夜畴、類方法等信息拖刃。資源包括資源類型和資源實(shí)例。
- how:授權(quán)/許可贪绘,規(guī)定了主體對資源的操作許可兑牡,權(quán)限離開資源沒有意義,如用戶查詢權(quán)限税灌、用戶添加權(quán)限均函、某個(gè)類方法的調(diào)用權(quán)限等,通過權(quán)限
可知主體對哪些資源有哪些操作許可
-
授權(quán)的方式
-
基于角色的訪問控制
-
RBAC基于角色的訪問控制(Role-Base Access Controll)是以角色為中心進(jìn)行訪問控制垄琐。
if(subject.hasRole("admin")){ //操作什么資源 }
-
-
- 基于資源的訪問控制(Resource-Based Access Control)是以資源為中心進(jìn)行訪問控制边酒。
```java
if(subject.isPermission("user:*:create")){
}
```
- 權(quán)限字符串
- 權(quán)限字符串的規(guī)則:資源標(biāo)識符:操作:資源實(shí)例標(biāo)識符经柴,意思是對哪個(gè)資源的哪個(gè)實(shí)例具有什么操作,權(quán)限字符串也可以使用*通配符狸窘。
- 用戶修改權(quán)限:user:create,或者user:create:*
- 用戶修改實(shí)例001的權(quán)限:user:update:001
- 用戶實(shí)例001的所有權(quán)限:user:*:001
- 權(quán)限字符串的規(guī)則:資源標(biāo)識符:操作:資源實(shí)例標(biāo)識符经柴,意思是對哪個(gè)資源的哪個(gè)實(shí)例具有什么操作,權(quán)限字符串也可以使用*通配符狸窘。
shiro中授權(quán)編程的方式
-
編程方式
if(subject.hasRole("admin")){ }
-
注解方式
@RequiresRoles("admin") public void hello(){}
-
標(biāo)簽方式
jsp/GSP 標(biāo)簽在jsp頁面通過相應(yīng)的標(biāo)簽方式完成 <shiro:hasRole name="admin"> </shiro:hasRole>
開發(fā)授權(quán)
- realm中實(shí)現(xiàn)
shiro與springboot進(jìn)行整合
實(shí)現(xiàn)的方式
springboot整合shiro需要通過Filter的方式對Url進(jìn)行攔截處理
實(shí)現(xiàn)過程
pom文件引入包
<!--添加shiro依賴-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-starter</artifactId>
<version>1.5.3</version>
</dependency>
<!--添加數(shù)據(jù)庫訪問-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.19</version>
</dependency>
定義配置類ShiroConfig
在配置類中主要配置shiro的攔截器、shiro安全管理器坯认、shiro訪問數(shù)據(jù)庫域翻擒、MD5加密
- 配置攔截器
/**
* 定義攔截器
* @param defaultWebSecurityManager
* @return
*/
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();
//給filter設(shè)置公共安全管理器
shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
//配置訪問權(quán)限
HashMap<String, String > 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;
}
- 注入安全管理器
//創(chuàng)建安全管理器
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(AuthorizingRealm realm){
DefaultWebSecurityManager defaultWebSecurityManager=new DefaultWebSecurityManager();
realm.setCredentialsMatcher(getCredentialsMatcher());
defaultWebSecurityManager.setRealm(realm);
return defaultWebSecurityManager;
}
- 創(chuàng)建自己的訪問數(shù)據(jù)庫域
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");//設(shè)置使用什么方式進(jìn)行加密
hashedCredentialsMatcher.setHashIterations(1024);//設(shè)置散列的次數(shù)
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
<!--添加ehcache緩存配置-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.5.3</version>
</dependency>
-
配置realm中開啟緩存
@Bean public AuthorizingRealm getAuthorizingRealm(){ CustomRealm customRealm = new CustomRealm(); customRealm.setCredentialsMatcher(redentialsMatcher());//設(shè)置認(rèn)證秘鑰md5+salt+散列 //開啟緩存 customRealm.setCachingEnabled(true);//開啟全局緩存 customRealm.setCacheManager(ehCacheManager()); customRealm.setAuthenticationCachingEnabled(true);//開啟認(rèn)證緩存 customRealm.setAuthenticationCacheName("AuthenticationCache");//設(shè)置認(rèn)證緩存的名字 customRealm.setAuthorizationCachingEnabled(true);//開啟授權(quán)緩存 customRealm.setAuthorizationCacheName("AuthorizationCache");//設(shè)置授權(quán)緩存的名字 customRealm.setCacheManager(new EhCacheManager());//設(shè)置緩存管理器 return customRealm; }
shiro整合redis
-
添加redis依賴
<!--添加redis緩存配置--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
-
redis實(shí)現(xiàn)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 <K, V> Cache<K, V> getCache(String s) throws CacheException { return new ReidsCacheShiro<K,V>(s,redisTemplate); } }
-
設(shè)置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<K,V> implements Cache<K,V> { 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<K> keys() { return null; } @Override public Collection<V> values() { return null; } }
-
shiroConfig中設(shè)置redisCacheManager
@Bean public CacheManager redisCacheManager(){ return new RedisCacheShiroManager(redisTemplate); } /** * 自定義realm實(shí)現(xiàn) * 1氓涣、設(shè)置MD5加密驗(yàn)證機(jī)制 * 2、開啟realm緩存 * @return */ @Bean public AuthorizingRealm getAuthorizingRealm(){ CustomRealm customRealm = new CustomRealm(); customRealm.setCredentialsMatcher(redentialsMatcher());//設(shè)置認(rèn)證秘鑰md5+salt+散列 //開啟緩存 customRealm.setCachingEnabled(true);//開啟全局緩存 //customRealm.setCacheManager(ehCacheManager()); customRealm.setCacheManager(redisCacheManager()); customRealm.setAuthenticationCachingEnabled(true);//開啟認(rèn)證緩存 customRealm.setAuthenticationCacheName("AuthenticationCache");//設(shè)置認(rèn)證緩存的名字 customRealm.setAuthorizationCachingEnabled(true);//開啟授權(quán)緩存 customRealm.setAuthorizationCacheName("AuthorizationCache");//設(shè)置授權(quán)緩存的名字 customRealm.setCacheManager(new EhCacheManager());//設(shè)置緩存管理器 return customRealm; }