1. 程式人生 > >【機房報修管理系統開發日誌】1.Shiro的自定義攔截不生效

【機房報修管理系統開發日誌】1.Shiro的自定義攔截不生效

我的環境


  • Shiro 1.4.0
  • SpringBoot 2.0.6


一、遇到的問題


在我剛寫好了Realm檔案和ShiroConfig檔案,做好了自定義攔截,程式碼如下所示
AdminRealm.java

package com.repairsystem.realm;

import com.repairsystem.entity.Administrator;
import com.repairsystem.entity.Permission;
import com.repairsystem.entity.Role;
import com.
repairsystem.service.AdministratorService; import com.repairsystem.service.PermissionService; import com.repairsystem.service.RoleService; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.springframework.beans.factory.annotation.Autowired; import javax.annotation.Resource; import java.util.HashSet; import java.util.List; import java.util.Set; /** * @author CheungChingYin * @date 2018/11/4 * @time 21:29 */
public class AdminRealm extends AuthorizingRealm { @Resource private AdministratorService adminService; @Resource private PermissionService permissionService; @Resource private RoleService roleService; /** * 為當前登入成功的使用者授予許可權和分配角色 * * @param principalCollection * @return */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { //獲得使用者手機 String phoneNum = (String) principalCollection.getPrimaryPrincipal(); Administrator admin = adminService.searchAdministratorByPhoneNum(phoneNum); Role role = roleService.searchRoleById(admin.getRoleId()); List<Permission> permissionList = permissionService.searchPermissionByRoleId(admin.getRoleId()); Set<String> roleSet = new HashSet<>(); roleSet.add(role.getRoleName()); Set<String> permissionSet = new HashSet<>(); for (Permission p : permissionList) { permissionSet.add(p.getPermissionName()); } SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); authorizationInfo.setRoles(roleSet); authorizationInfo.setRoles(permissionSet); return authorizationInfo; } /** * 用來驗證當前登入的使用者,獲取認證資訊 * * @param authenticationToken * @return * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { //通過Token獲取管理員手機號 String adminPhoneNum = (String) authenticationToken.getPrincipal(); //根據管理員手機號查詢管理員資訊 Administrator admin = adminService.searchAdministratorByPhoneNum(adminPhoneNum); if (admin != null) { SecurityUtils.getSubject().getSession().setAttribute("admin", admin); AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(admin.getAdminPhone(), admin.getAdminPassword(), "AdminRealm"); return authcInfo; } else { return null; } } }

ShiroConfig .java

package com.repairsystem.config;

import com.repairsystem.realm.AdminRealm;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author CheungChingYin
 * @date 2018/11/5
 * @time 14:20
 */
@Configuration
public class ShiroConfig {

    private static final Logger LOGGER = LoggerFactory.getLogger(ShiroConfig.class);

    @Bean
    public ShiroFilterFactoryBean shiroFilter(@Qualifier("getSecurityManager") SecurityManager securityManager) {
        //定義shiroFilterFactoryBean
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();

        //設定自定義的 securityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        // 設定預設登入的 URL,身份認證失敗會訪問該 URL
        shiroFilterFactoryBean.setLoginUrl("/login");
        // 設定成功之後要跳轉的連結
        shiroFilterFactoryBean.setSuccessUrl("/main");
        // 設定未授權介面,許可權認證失敗會訪問該 URL
        shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized");

        // LinkedHashMap 是有序的,進行順序攔截器配置
        Map<String,String> filterChainMap = new LinkedHashMap<String, String>();

        // 配置可以匿名訪問的地址,可以根據實際情況自己新增,放行一些靜態資源等,anon 表示放行
        filterChainMap.put("/css/**", "anon");
        filterChainMap.put("/imgs/**", "anon");
        filterChainMap.put("/js/**", "anon");
        filterChainMap.put("/swagger-ui.html", "anon");
        filterChainMap.put("/swagger-*/**", "anon");
        filterChainMap.put("/swagger-ui.html/**", "anon");
        // 登入 URL 放行
        filterChainMap.put("/login", "anon");

        // 以“/user/admin” 開頭的使用者需要身份認證,authc 表示要進行身份認證
        filterChainMap.put("/user/admin*", "authc");
        ///user/student” 開頭的使用者需要角色認證,是“admin”才允許
        filterChainMap.put("/user/student*/**", "roles[admin]");
        // “/user/teacher” 開頭的使用者需要許可權認證,是“user:create”才允許
        filterChainMap.put("/user/teacher*/**", "perms[\"user:create\"]");

        // 配置 logout 過濾器
        filterChainMap.put("/logout", "logout");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainMap);

        LOGGER.info("====shiroFilterFactoryBean註冊完成====");
        return shiroFilterFactoryBean;

    }


    /**
     * 注入自定義Realm
     *
     * @return
     */
    @Bean(name = "adminRealm")
    public AdminRealm getAdminRealm() {
        AdminRealm adminRealm = new AdminRealm();
        LOGGER.info("====AdminRealm註冊完成=====");
        return adminRealm;
    }

    /**
     * 注入安全管理器
     *
     * @return
     */
    @Bean(name = "getSecurityManager")
    public SecurityManager getSecurityManager(@Qualifier("adminRealm") AdminRealm adminRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(adminRealm);
        LOGGER.info("====securityManager註冊完成====");
        return securityManager;
    }



}

一切程式碼都沒問題,SpringBoot也能夠正常啟動,但是我是自定義了/swagger-ui.html是匿名訪問,是不會被攔截的,當時我在瀏覽器輸入訪問/swagger-ui.html的時候,會自動跳轉到login.jsp(注意這裡),輸入其他地址也是跳轉回login.jsp



二、如何解決


請檢查你的pom.xml配置檔案

<!-- shiro -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring-boot-starter</artifactId>
            <version>1.4.0</version>
        </dependency>

如果你引入上面這個Shiro,請留意它的<artifactId>標籤是shiro-spring-boot-starter,這個是配合SpringBoot的Shiro,它會自動幫你配置ShiroConfig導致自己自定義配置失效,所以通過Maven匯入Shiro應該使用以下程式碼

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.4.0</version>
</dependency>



三、解決問題的過程

1.一開始我使用Maven匯入了這個Shiro

<!-- shiro -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring-boot-starter</artifactId>
            <version>1.4.0</version>
        </dependency>

在這裡插入圖片描述
執行的時候發現報上面的錯誤(注意紅框,當時我就是沒有注意紅框搞了好久都不能解決問題)
然後我就上網尋找解答
發現了這個問題《springboot1.5.13整合shiro》和我遇到的問題一樣,解決方法是
在這裡插入圖片描述
配置之後發現SpringBoot執行沒問題

2.嘗試開啟沒有攔截的頁面

發現無論是開啟什麼頁面,都會返回到/login.jsp
然後就開始瘋狂去找問題了(沒有報錯的BUG最可怕了)
直到我遇到這篇文章《教你 Shiro 整合 SpringBoot,避開各種坑》
他的程式碼裡面有這樣一個註釋
在這裡插入圖片描述
然後我就想了會不會是被當成了預設配置呢?
在我除去了步驟1的解決方法後發現
在這裡插入圖片描述
有一個叫做autoconfig,也就是做會SpringBoot自動幫你做預設配置,所以才會這樣。於是就有了上面的解決方法。