springboot整合Shiro

shiro权限控制架构

shiro实现的认证

1、从类的继承关系可以看出自定义的Realm只需要实现AuthorizingRealm类即可。

Realm继承关系.png

2、只需要实现下列两个方法即可
doGetAuthorizationInfo 授权
doGetAuthenticationInfo 认证

shiro中的加密

  1. md5加密一般用来加密和做校验和

    • MD5算法不可逆,内容相同无论执行多少次MD5加密生成的结果始终一致。
      例如:可以对文件进行文件加密,保证文件的内容不被篡改
    • 网上常见的MD5解密,只是做了把简单的字符串进行穷举解密
    • MD5加密完始终是一个16进制的32位长度字符串

Shiro中如何使用MD5加密认证

  1. 用户登录时的处理在Realm中添加秘钥认证器
//给安全管理器设置realm
     CustomerMd5Realm customerMd5Realm=new CustomerMd5Realm();
     //自定义MD5秘钥匹配器
     HashedCredentialsMatcher hashedCredentialsMatcher=new HashedCredentialsMatcher();
     hashedCredentialsMatcher.setHashAlgorithmName("md5");//设置使用什么方式进行加密
     hashedCredentialsMatcher.setHashIterations(1024);//设置散列的次数
     customerMd5Realm.setCredentialsMatcher(hashedCredentialsMatcher);
  1. 在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中实现授权

  1. 授权的概念

    • 授权,即访问控制,控制谁能访问哪些资源,主体进行身份认证后需要分配权限方可访问系统的资源,对于某些资源没有权限是没有权限访问的
    • 授权可以简单的理解为Who对What进行How操作
      • who:即主体Subject 主体需要访问系统中的资源。
      • what:即资源Resource,如系统菜单、页面、按钮、类方法等信息。资源包括资源类型和资源实例。
      • how:授权/许可,规定了主体对资源的操作许可,权限离开资源没有意义,如用户查询权限、用户添加权限、某个类方法的调用权限等,通过权限
        可知主体对哪些资源有哪些操作许可
  2. 授权的方式

    • 基于角色的访问控制

      • RBAC基于角色的访问控制(Role-Base Access Controll)是以角色为中心进行访问控制。

        if(subject.hasRole("admin")){
            //操作什么资源
        }
        
 - 基于资源的访问控制(Resource-Based Access Control)是以资源为中心进行访问控制。

   ```java
   if(subject.isPermission("user:*:create")){
       
   }
   ```
  1. 权限字符串
    • 权限字符串的规则:资源标识符:操作:资源实例标识符,意思是对哪个资源的哪个实例具有什么操作,权限字符串也可以使用*通配符。
      • 用户修改权限:user:create,或者user:create:*
      • 用户修改实例001的权限:user:update:001
      • 用户实例001的所有权限:user:*:001

shiro中授权编程的方式

  • 编程方式

    if(subject.hasRole("admin")){
        
    }
    
  • 注解方式

    @RequiresRoles("admin")
    public void hello(){}
    
  • 标签方式

    jsp/GSP 标签在jsp页面通过相应的标签方式完成
    <shiro:hasRole name="admin">
    
    </shiro:hasRole>
    

开发授权

  1. realm中实现

shiro与springboot进行整合

实现的方式

springboot整合shiro需要通过Filter的方式对Url进行拦截处理

实现过程

pom文件引入包

 <!--添加shiro依赖-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring-boot-starter</artifactId>
            <version>1.5.3</version>
        </dependency>
        <!--添加数据库访问-->
        <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访问数据库域、MD5加密

  • 配置拦截器
 /**
     * 定义拦截器
     * @param defaultWebSecurityManager
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();
        //给filter设置公共安全管理器
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
        //配置访问权限
        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;
    }
  • 注入安全管理器
//创建安全管理器
@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
<!--添加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());//设置认证秘钥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依赖

      <!--添加redis缓存配置-->
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-data-redis</artifactId>
      </dependency>
    
  • 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 <K, V> Cache<K, V> getCache(String s) throws CacheException {
            return new ReidsCacheShiro<K,V>(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<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中设置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;
      }
    

shiro 集成验证码

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,682评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,277评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,083评论 0 355
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,763评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,785评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,624评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,358评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,261评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,722评论 1 315
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,900评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,030评论 1 350
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,737评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,360评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,941评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,057评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,237评论 3 371
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,976评论 2 355