Shiro integrates the Web

Shiro's Web Process

image.png

Shiro integrates SSM

  • Prepare SSM configuration
  • Prepare the classic five tables (see basic use of Shiro ) and complete the test
  • Prepare Shiro's configuration
    • core filter

      <!--    配置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>
      
    • Prepare shiroFilter instance

      <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
      	.....
      </bean>
      
    • Inject SecurityManager, login page path, filter chain

      <!--    构建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>
      
    • Modify ShiroRealm's simulated database operation to interact with the database (see Shiro basic usage )

    • Write login function and test the effect

      @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 integrates SpringBoot

  • Build SpringBoot project
  • Configure Shiro to integrate SpringBoot content
    @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 authorization method

filter chain

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

Custom filters

  • Implement custom filters based on 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;
        }
    }
    
  • Configure custom filters to 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;
        }
    }
    

annotation

  • When annotation is authorized, it is based on proxying the Controller class, and performs permission verification on the request in the pre-enhancement.

  • Because we use SpringBoot's testing method, we can add annotations directly to the Controller method.

    @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)
    
  • Annotations take effect by default in Spring Boot because support for annotations has been configured in automatic assembly.

    @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);
        }
    }
    
  • The annotation form cannot locate the error page information to 401.html, because the configured path is only valid for the filter chain, and the annotation is invalid. In order to achieve the effect of friendly prompts, you can configure exception handlers, @RestControllerAdvice, @ControllerAdvice

remember me

Remember that after I turn it on, I can use the user filter to intercept some pages with a relatively lower security level. As long as I have logged in, I can access it without re-logging in.

Prepare two interfaces

    @GetMapping("/rememberMe")
    public String rememberMe(){
    
    
        return "rememberMe!!!";
    }

    @GetMapping("/authentication")
    public String authentication(){
    
    
        return "authentication!!!";
    }

Configure different filters

    filterChainDefinitionMap.put("/item/rememberMe","user");
    filterChainDefinitionMap.put("/item/authentication","authc");

Add a remember me button to the page, and add the rememberMe effect when logging in

<form action="/user/login" method="post">
    用户名:<input  name="username" />  <br />
    密码:<input name="password" />  <br />
    记住我:<input type="checkbox" name="rememberMe" value="on" />  <br />
    <button type="submit">登录</button>
</form>

Guess you like

Origin blog.csdn.net/qq_28314431/article/details/133045554