【機房報修管理系統開發日誌】1.Shiro的自定義攔截不生效
阿新 • • 發佈:2018-11-07
我的環境
- 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自動幫你做預設配置,所以才會這樣。於是就有了上面的解決方法。