Shiro 整合 Web

简介: Shiro整合SSM

Shiro的Web流程

image.png

Shiro整合SSM

  • 准备SSM的配置
  • 准备经典五张表(见[Shiro基本使用]),完成测试
  • 准备Shiro的配置

    • 核心过滤器

      <!--    配置Shiro整合web的过滤器-->
      <filter>
          <!--        默认情况下,请求到达这个过滤器,会去Spring容器中名字为filter-name的实例去处理-->
          <filter-name>shiroFilter</filter-name>
          <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
      </filter>
      <filter-mapping>
          <filter-name>shiroFilter</filter-name>
          <url-pattern>/*</url-pattern>
      </filter-mapping>
    • 准备shiroFilter实例

      <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
          .....
      </bean>
    • 注入SecurityManager,登录页面路径,过滤器链

      <!--    构建realm-->
      <bean id="realm" class="com.xxx.realm.ShiroRealm" />
      
      <!--    构建securityManager-->
      <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
          <property name="realm" ref="realm"/>
      </bean>
      
      <!--    构建ShiroFilter实例-->
      <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
          <property name="securityManager" ref="securityManager"/>
          <property name="loginUrl" value="/login.html" />
          <property name="filterChainDefinitionMap">
              <map>
                  <entry key="/login.html" value="anon" />
                  <entry key="/user/**" value="anon" />
                  <entry key="/**" value="authc" />
              </map>
          </property>
      </bean>
    • 将ShiroRealm的模拟数据库操作,修改为与数据库交互(见[Shiro基本使用]
    • 编写登录功能,并测试效果

      @PostMapping("/login")
      public String login(String username,String password){
          // 执行Shiro的认证操作
          //1. 直接基于SecurityUtils获取subject主体,不需要手动的将SecurityManager和SecurityUtils手动整合,Spring已经奥丁
          Subject subject = SecurityUtils.getSubject();
      
          //2. 发起认证
          try {
              subject.login(new UsernamePasswordToken(username,password));
              return "SUCCESS";
          } catch (UnknownAccountException exception){
              return "username fail!!!";
          } catch (IncorrectCredentialsException exception){
              return "password fail!!!";
          } catch (AuthenticationException e) {
              return "donot know...!!!";
          }
      }

Shiro整合SpringBoot

  • 搭建SpringBoot工程
  • 配置Shiro整合SpringBoot内容

    @Configuration
    public class ShiroConfig {
    
        @Bean
        public DefaultWebSecurityManager securityManager(ShiroRealm realm){
            DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
            securityManager.setRealm(realm);
            return securityManager;
        }
    
        @Bean
        public DefaultShiroFilterChainDefinition shiroFilterChainDefinition(){
            DefaultShiroFilterChainDefinition shiroFilterChainDefinition = new DefaultShiroFilterChainDefinition();
    
            Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
            filterChainDefinitionMap.put("/login.html","anon");
            filterChainDefinitionMap.put("/user/**","anon");
            filterChainDefinitionMap.put("/**","authc");
    
            shiroFilterChainDefinition.addPathDefinitions(filterChainDefinitionMap);
    
            return shiroFilterChainDefinition;
        }
    }

Shiro授权方式

过滤器链

public enum DefaultFilter {
    // ....
    perms(PermissionsAuthorizationFilter.class),
    roles(RolesAuthorizationFilter.class),
    // ....
}
filterChainDefinitionMap.put("/item/select","roles[超级管理员,运营]");
filterChainDefinitionMap.put("/item/delete","perms[item:delete,item:insert]");

image.png

自定义过滤器

  • 仿照RolesAuthorizationFilter实现自定义过滤器

    /**
     * 在要求的多个角色中,有一个满足要求,就放行
     * @author zjw
     * @description
     */
    public class RolesOrAuthorizationFilter extends AuthorizationFilter {
        @Override
        protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
            // 获取主体subject
            Subject subject = getSubject(request, response);
            // 将传入的角色转成数组操作
            String[] rolesArray = (String[]) mappedValue;
            // 健壮性校验
            if (rolesArray == null || rolesArray.length == 0) {
                return true;
            }
            // 开始校验
            for (String role : rolesArray) {
                if(subject.hasRole(role)){
                    return true;
                }
            }
    
            return false;
        }
    }
  • 将自定义过滤器配置给Shiro

    @Configuration
    public class ShiroConfig {
    
        @Bean
        public DefaultWebSecurityManager securityManager(ShiroRealm realm){
            DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
            securityManager.setRealm(realm);
            return securityManager;
        }
    
        @Bean
        public DefaultShiroFilterChainDefinition shiroFilterChainDefinition(){
            DefaultShiroFilterChainDefinition shiroFilterChainDefinition = new DefaultShiroFilterChainDefinition();
    
            Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
            filterChainDefinitionMap.put("/login.html","anon");
            filterChainDefinitionMap.put("/user/**","anon");
            filterChainDefinitionMap.put("/item/select","rolesOr[超级管理员,运营]");
            filterChainDefinitionMap.put("/item/delete","perms[item:delete,item:insert]");
            filterChainDefinitionMap.put("/**","authc");
    
            shiroFilterChainDefinition.addPathDefinitions(filterChainDefinitionMap);
    
            return shiroFilterChainDefinition;
        }
    
        @Value("#{ @environment['shiro.loginUrl'] ?: '/login.jsp' }")
        protected String loginUrl;
    
        @Value("#{ @environment['shiro.successUrl'] ?: '/' }")
        protected String successUrl;
    
        @Value("#{ @environment['shiro.unauthorizedUrl'] ?: null }")
        protected String unauthorizedUrl;
  @Bean
  protected ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager,ShiroFilterChainDefinition shiroFilterChainDefinition) {
      //1. 构建ShiroFilterFactoryBean工厂
      ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean();

      //2. 设置了大量的路径
      filterFactoryBean.setLoginUrl(loginUrl);
      filterFactoryBean.setSuccessUrl(successUrl);
      filterFactoryBean.setUnauthorizedUrl(unauthorizedUrl);

      //3. 设置安全管理器
      filterFactoryBean.setSecurityManager(securityManager);

      //4. 设置过滤器链
      filterFactoryBean.setFilterChainDefinitionMap(shiroFilterChainDefinition.getFilterChainMap());

      //5. 设置自定义过滤器 , 这里一定要手动的new出来这个自定义过滤器,如果使用Spring管理自定义过滤器,会造成无法获取到Subject
      filterFactoryBean.getFilters().put("rolesOr",new RolesOrAuthorizationFilter());

      //6. 返回工厂
      return filterFactoryBean;
  }

}

 

##  注解

* 注解进行授权时,是基于对Controller类进行代理,在前置增强中对请求进行权限校验
* 因为咱们使用SpringBoot的测试方式,直接在Controller方法上添加注解即可

@GetMapping("/update")
@RequiresRoles(value = {"超级管理员","运营"})
public String update(){

  return "item Update!!!";

}

@GetMapping("/insert")
@RequiresRoles(value = {"超级管理员","运营"},logical = Logical.OR)
public String insert(){

  return "item Update!!!";

}

// @RequiresPermissions(value = "",logical = Logical.AND)

* 在SpringBoot中注解默认就生效,是因为自动装配中,已经配置好了对注解的支持

@Configuration
@ConditionalOnProperty(name = "shiro.annotations.enabled", matchIfMissing = true)
public class ShiroAnnotationProcessorAutoConfiguration extends AbstractShiroAnnotationProcessorConfiguration {

  @Bean
  @DependsOn("lifecycleBeanPostProcessor")
  @ConditionalOnMissingBean
  @Override
  public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
      return super.defaultAdvisorAutoProxyCreator();
  }

  @Bean
  @ConditionalOnMissingBean
  @Override
  public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
      return super.authorizationAttributeSourceAdvisor(securityManager);
  }

}

* 注解的形式无法将错误页面的信息定位到401.html,因为配置的这种路径,只针对过滤器链有效,注解无效。为了实现友好提示的效果,可以配置异常处理器,@RestControllerAdvice,@ControllerAdvice

 
## 记住我

记住我在开启后,可以针对一些安全级别相对更低的页面采用user过滤器拦截,只要登录过,不需要重新登录就可以访问。


准备两个接口
@GetMapping("/rememberMe")
public String rememberMe(){
    return "rememberMe!!!";
}

@GetMapping("/authentication")
public String authentication(){
    return "authentication!!!";
}
配置不同的过滤器
filterChainDefinitionMap.put("/item/rememberMe","user");
filterChainDefinitionMap.put("/item/authentication","authc");
在页面追加记住我按钮,并且在登录是,添加rememberMe效果
用户名:
密码:
记住我:
相关文章
|
安全 算法 Oracle
【WEB安全】Apache Shiro 反序列化漏洞(上)
Apache Shiro是一款开源企业常见JAVA安全框架,提供身份验证、授权、密码学和会话管理。java中的权限框架有SpringSecurity和Shiro,由于Spring功能强大但复杂,Shiro的简单强大,扩展性好因此用的还是很多。
738 0
【WEB安全】Apache Shiro 反序列化漏洞(上)
|
6月前
|
安全 Java 网络安全
【Shiro】第四章 Web项目集成Shiro
【Shiro】第四章 Web项目集成Shiro
94 1
|
安全 Java
【Shiro】第四章 Web项目集成Shiro(四)
【Shiro】第四章 Web项目集成Shiro(四)
100 0
|
数据安全/隐私保护
【Shiro】第四章 Web项目集成Shiro(三)
【Shiro】第四章 Web项目集成Shiro(三)
75 0
|
Java
【Shiro】第四章 Web项目集成Shiro(二)
【Shiro】第四章 Web项目集成Shiro(二)
69 0
|
网络安全 网络架构
【Shiro】第四章 Web项目集成Shiro(一)
【Shiro】第四章 Web项目集成Shiro
85 0
|
前端开发 Java
Shiro框架学习笔记(三)与web集成之后进行简单的身份验证
Shiro框架学习笔记(三)与web集成之后进行简单的身份验证
Shiro框架学习笔记(三)与web集成之后进行简单的身份验证
|
安全 Oracle 关系型数据库
【WEB安全】Apache Shiro 反序列化漏洞(下)
Apache Shiro是一款开源企业常见JAVA安全框架,提供身份验证、授权、密码学和会话管理。java中的权限框架有SpringSecurity和Shiro,由于Spring功能强大但复杂,Shiro的简单强大,扩展性好因此用的还是很多。
387 0
【WEB安全】Apache Shiro 反序列化漏洞(下)
|
安全 Java Shell
【WEB安全】Apache Shiro 反序列化漏洞(中)
Apache Shiro是一款开源企业常见JAVA安全框架,提供身份验证、授权、密码学和会话管理。java中的权限框架有SpringSecurity和Shiro,由于Spring功能强大但复杂,Shiro的简单强大,扩展性好因此用的还是很多。
487 0
【WEB安全】Apache Shiro 反序列化漏洞(中)