SpringBoot之集成Shiro中出現的一個問題logout沒有作用(實際上時authcBasic導致的問題)

1.聲明

當前的內容用於本人學習和使用之用,關於本人在一次偶然的機會發現的一個bug,一個關於shiro的bug(SpringBoot中集成Shiro的時候調用logout出現的bug)

2.pom文件配置

<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>2.2.5.RELEASE</version>
	<relativePath /> <!-- lookup parent from repository -->
</parent>
<!--  shiro的配置 -->
<dependency>
	<groupId>org.apache.shiro</groupId>
	<artifactId>shiro-core</artifactId>
	<version>1.4.1</version>
</dependency>
<!-- 使用註解版的權限管理需要開啓aop -->
<dependency>
	<groupId>org.apache.shiro</groupId>
	<artifactId>shiro-aspectj</artifactId>
	<version>1.4.1</version>
</dependency>
<dependency>
	<groupId>org.apache.shiro</groupId>
	<artifactId>shiro-spring</artifactId>
	<version>1.4.1</version>
</dependency>
<!-- 配置shiro的會話緩存 -->
<dependency>
	<groupId>org.apache.shiro</groupId>
	<artifactId>shiro-ehcache</artifactId>
	<version>1.4.1</version>
</dependency>
		

springboot2.2.5.RELEASE和shiro1.4.1集成

3.ShiroConfig文件和其他的配置文件

@Configuration
@ConditionalOnClass({ SecurityManager.class, ShiroFilterFactoryBean.class, AuthorizationAttributeSourceAdvisor.class })
public class ShiroConfig {

	// 啓動基於ini配置的方式認證,這裏可以使用jdbc方式進行身份的驗證
	public Realm realm() {

		/*
		 * JdbcRealm jdbcRealm = new JdbcRealm();
		 * jdbcRealm.setPermissionsLookupEnabled(true);
		 * jdbcRealm.setDataSource(dataSource);
		 */
		// 開啓默認自動查找權限

		// 或者使用自定義的Realm方式
		IniRealm iniRealm = new IniRealm("classpath:shiro.ini");
		/*
		 * iniRealm.setAuthenticationCachingEnabled(true);
		 * iniRealm.setAuthorizationCachingEnabled(true);
		 */
		return iniRealm;
	}

	// 創建校驗管理器
	@Bean
	public DefaultWebSecurityManager securityManager() {
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		securityManager.setRealm(realm());
		securityManager.setSessionManager(defaultWebSessionManager());
		return securityManager;
	}

	// 創建Shiro過濾器

	@Bean
	public ShiroFilterFactoryBean shiroFilterFactoryBean(@Autowired DefaultWebSecurityManager securityManager) {
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
		shiroFilterFactoryBean.setSecurityManager(securityManager);

		Map<String, String> map = new HashMap<String, String>(); // 登出 //
		//map.put("/logout", "logout"); // 默認的退出登錄方式,使用spring方式實現
		map.put("/**", "authcBasic"); // 對所有用戶認證 // 登錄頁面使用get方式
		shiroFilterFactoryBean.setLoginUrl("/login"); // 首頁get方式
		shiroFilterFactoryBean.setSuccessUrl("/index"); // 錯誤頁面,認證不通過跳轉
		shiroFilterFactoryBean.setUnauthorizedUrl("/error");
		shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
		return shiroFilterFactoryBean;
	}

	@Bean
	public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(
			@Autowired DefaultWebSecurityManager securityManager) {
		AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
		authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
		return authorizationAttributeSourceAdvisor;
	}
}

shiro.ini配置文件

[main]
authcBasic.applicationName=please login
sessionManager=org.apache.shiro.web.session.mgt.DefaultWebSessionManager
sessionDAO=org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO
sessionDAO.activeSessionsCacheName=shiro-activeSessionCache
sessionManager.sessionDAO=sessionDAOcacheManager=org.apache.shiro.cache.ehcache.EhCacheManagercacheManager.cacheManagerConfigFile=classpath:shiroehcache.xmlsecurityManager.cacheManager=sessionDAO cacheManager=org.apache.shiro.cache.ehcache.EhCacheManager cacheManager.cacheManagerConfigFile=classpath:shiro-ehcache.xml securityManager.cacheManager=cacheManager
[users]
admin=admin,admin
user=user,user
[roles]
admin=insert,update,delete,select
user=select
[urls]
#/login=anon
#/logout=logout
#/unauthorized=anon
#/static/**=anon
#/authenticated=authc
#直接使用authcBasic,就是會彈出認證的輸入框
#/role=authcBasic,roles[admin]
#/permission=authc,perms[“user:create”]

shiro-ehcache.xml

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
         updateCheck="false">
<cache name="shiro-activeSessionCache"
		maxEntriesLocalHeap="10000"
		overflowToDisk="false"
		eternal="false"
		diskPersistent="false"
		timeToLiveSeconds="0"
		timeToIdleSeconds="0"
		statistics="true"/>
</ehcache>

4.創建訪問的ShiroController

@Controller
public class ShiroController {
	@RequiresRoles(value = { "admin" }) 
	@RequestMapping("/getShiroSubject")
	@org.springframework.web.bind.annotation.ResponseBody
	public ResponseBody getShiroSubject() {
		Subject subject = SecurityUtils.getSubject();
		Object loginUser = subject.getPrincipal();
		// 獲取當前登錄的用戶,如何獲取會話中的權限
		return ResponseBodyBuilder.instance().ok(loginUser);
	}

	@RequestMapping("/getDatas")
	@org.springframework.web.bind.annotation.ResponseBody
	public ResponseBody getDatas() {
		// 獲取當前登錄的用戶,如何獲取會話中的權限
		return ResponseBodyBuilder.instance().ok("成功獲取數據");
	}
	// 退出shiro控制

	@RequestMapping("/logout")
	public String logout() {
		Subject subject = SecurityUtils.getSubject(); 
		subject.logout();
		return "redirect:login";
	}

}

5.重現當前的問題logout問題

1.訪問logout

在這裏插入圖片描述
2.由於上面logout是成功的(但是這個地方卻可以訪問)
在這裏插入圖片描述
在這裏插入圖片描述
連帶有註解的@RequiresRoles(value = { "admin" }) 都成功了,這是什麼鬼?

一個非常詭異的問題產生了,本人通過debug發現確實調用了方法,也沒有報錯,但是就是shiro都是允許訪問的(這是一個bug)

再次訪問logout發現還是可以訪問
在這裏插入圖片描述

6.清空瀏覽器緩存然後再訪問

在這裏插入圖片描述
需要輸入密碼和用戶名

再次登錄和退出,以及再次訪問又發現可以訪問了
在這裏插入圖片描述

通過不停的調試和排除其他東西,查看原生的servlet中logout是可以執行的(基於ShiroFilter方式是可以實現的)

最後本人無法解決這個問題,所以本人認爲這應該就是一個bug

7.解決方案

通過本人的不屑努力,終於發現當前出現問題的地方,在於authcBasic原因是Basic驗證時基於HTTP的和SHIRO無關!

參考:解決方案

8.修改當前的shiro.ini配置認證方式爲authc

[main]
authcBasic.applicationName=please login
authc.loginUrl=/login
sessionManager=org.apache.shiro.web.session.mgt.DefaultWebSessionManager
sessionDAO=org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO
sessionDAO.activeSessionsCacheName=shiro-activeSessionCache
sessionManager.sessionDAO=sessionDAOcacheManager=org.apache.shiro.cache.ehcache.EhCacheManagercacheManager.cacheManagerConfigFile=classpath:shiroehcache.xmlsecurityManager.cacheManager=sessionDAO cacheManager=org.apache.shiro.cache.ehcache.EhCacheManager cacheManager.cacheManagerConfigFile=classpath:shiro-ehcache.xml securityManager.cacheManager=cacheManager
sessionManager.sessionIdCookie.path=/
[users]
admin=admin,admin
user=user,user
[roles]
admin=insert,update,delete,select
user=select
[urls]
#/login=anon

修改ShiroConfig文件中的ShiroFilterFactoryBean

@Bean
	public ShiroFilterFactoryBean shiroFilterFactoryBean() {
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
		shiroFilterFactoryBean.setSecurityManager(securityManager());

		Map<String, String> map = new HashMap<String, String>(); // 登出 //
		//map.put("/logout", "logout"); // 默認的退出登錄方式,使用spring方式實現
		map.put("/**", "authc"); // 對所有用戶認證 // 登錄頁面使用get方式
		//map.put("/**", "authcBasic");
		// 注意這裏的authcBasic,該驗證是BASIC認證都是需要關閉瀏覽器才清除保存的用戶認證信息,跟是否使用shiro無關!
		shiroFilterFactoryBean.setLoginUrl("/login"); // 首頁get方式authc.loginUrl = /login
		shiroFilterFactoryBean.setSuccessUrl("/index"); // 錯誤頁面,認證不通過跳轉
		shiroFilterFactoryBean.setUnauthorizedUrl("/error");
		shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
		return shiroFilterFactoryBean;
	}

9.創建登錄login.html和對應的@RequestMapping

再當前的resources中創建一個文件爲login.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<form action="/login" method="post">
		<input type="text" name="username"/><br/>
		<input type="password" name="password"/><br/>
		<input type="submit" value="登錄"/>
	</form>
</body>
</html>

對應的@RequestMapping

@RequestMapping(value = "/login", method = RequestMethod.GET)
	public String login() {
		return "login.html";
	}

	@RequestMapping(value = "/login", method = RequestMethod.POST)
	@org.springframework.web.bind.annotation.ResponseBody
	ResponseBody login(String username, String password) {
		Subject subject = SecurityUtils.getSubject();
		subject.login(new UsernamePasswordToken(username, password));
		return ResponseBodyBuilder.instance().ok("登錄成功!");

	}

10.測試

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

11.總結

1.在springboot中配置Shiro的時候,一定要注意認證方式,不同的認證方式會產生不同的效果(這裏的authcBasic就是一個只和Http有關的認證方式)

2.一般在web環境中只需要使用authc認證即可小心authcBasic(雖然比較簡單,但是在前後端分離的時候容易出現問題)

2.當前內容終於解決了

以上純屬個人見解,如有問題請聯繫本人!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章