基于SpringBoot2的Shiro最簡配置操作(兩個文件)
基礎(chǔ)環(huán)境:依賴
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.1.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent>
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-starter</artifactId> <version>1.4.0</version> </dependency>
如果不是前后端分離,要實現(xiàn)頁面級的權(quán)限控制,則加入以下依賴就可以使用shiro的權(quán)限標(biāo)簽了(記得在html頭部加上相應(yīng)約束:
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="Thymeleaf" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro" lang="en"> ): <dependency> <groupId>com.github.theborakompanioni</groupId> <artifactId>thymeleaf-extras-shiro</artifactId> <version>2.0.0</version> </dependency>
Realm:認(rèn)證鑒權(quán)器
package com.rz.monomer.modules.shiro; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.rz.monomer.modules.user.entity.SysUserInfo; import com.rz.monomer.modules.user.entity.SysUserRole; import com.rz.monomer.modules.user.service.SysButtonInfoService; import com.rz.monomer.modules.user.service.SysUserInfoService; import com.rz.monomer.modules.user.service.SysUserRoleService; import lombok.extern.slf4j.Slf4j; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.SimpleAuthenticationInfo; 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 java.util.Set; import java.util.stream.Collectors; /** * 認(rèn)證、鑒權(quán)類(必須) * * @author sunziwen * @version 1.0 * @date 2019/11/14 14:06 **/ @Slf4j public class ShiroRealm extends AuthorizingRealm { //以下三個服務(wù)是普通Dao查詢,從數(shù)據(jù)庫查詢用戶及其角色權(quán)限信息(這個類沒有自動注入,需要在下個文件中手動注入) private SysUserInfoService userInfoService; private SysButtonInfoService buttonInfoService; private SysUserRoleService userRoleService; public ShiroRealm(SysUserInfoService userInfoService, SysButtonInfoService buttonInfoService, SysUserRoleService userRoleService) { this.userInfoService = userInfoService; this.buttonInfoService = buttonInfoService; this.userRoleService = userRoleService; } @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { log.info("check authorization info"); SimpleAuthorizationInfo authInfo = new SimpleAuthorizationInfo(); // 獲取當(dāng)前用戶 SysUserInfo userInfo = (SysUserInfo) principals.getPrimaryPrincipal(); // 查詢角色信息 Set<Long> userRoles = userRoleService.list(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getUserId, userInfo.getId())) .stream() .map(SysUserRole::getRoleId) .collect(Collectors.toSet()); //角色所有權(quán)限 Set<String> perms = buttonInfoService.getPermsByRoles(userRoles); authInfo.addStringPermissions(perms); return authInfo; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { log.info("check authentication info"); String username = (String) token.getPrincipal(); // 獲取用戶信息 SysUserInfo user = userInfoService.getOne(new LambdaQueryWrapper<SysUserInfo>().eq(SysUserInfo::getUsername, username)); if (user == null) { return null; } /*SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user, user.getPassword(), ByteSource.Util.bytes(654321), getName());*/ SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user, user.getPassword(), getName()); return authenticationInfo; } }
WebSecurityManager:安全管理器
package com.rz.monomer.modules.shiro; import com.rz.monomer.modules.user.service.SysButtonInfoService; import com.rz.monomer.modules.user.service.SysUserInfoService; import com.rz.monomer.modules.user.service.SysUserRoleService; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.filter.authc.FormAuthenticationFilter; import org.apache.shiro.web.filter.authc.LogoutFilter; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.servlet.Filter; import java.util.LinkedHashMap; import java.util.Map; /** * Shiro配置類(必須) * * @author sunziwen * @version 1.0 * @date 2019/11/14 14:08 **/ @Configuration @Slf4j @AllArgsConstructor public class WebSecurityManager { private SysUserInfoService userInfoService; private SysButtonInfoService buttonInfoService; private SysUserRoleService userRoleService; /** * 安全管理器 */ @Bean public DefaultWebSecurityManager securityManager() { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(realm()); return securityManager; } /** * 認(rèn)證鑒權(quán)器(安全管理器的依賴) */ @Bean public ShiroRealm realm() { return new ShiroRealm(userInfoService, buttonInfoService, userRoleService); } /** * 配置攔截規(guī)則 */ @Bean public ShiroFilterFactoryBean filter(org.apache.shiro.mgt.SecurityManager securityManager) { log.info("config shiro filter"); ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); // 定義URL攔截鏈 Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>(); // 允許匿名用戶訪問首頁 filterChainDefinitionMap.put("/shiro/index", "anon"); // 定義注銷路徑 filterChainDefinitionMap.put("/shiro/logout", "logout"); // 所有用戶界面都需要身份驗證,否則會跳轉(zhuǎn)到loginurl,由FormAuthenticationFilter處理 filterChainDefinitionMap.put("/shiro/user/**", "authc"); // 為login路徑定義攔截,由FormAuthenticationFilter處理 filterChainDefinitionMap.put("/shiro/login", "authc"); // 所有vip路徑要求具備vip角色權(quán)限 filterChainDefinitionMap.put("/shiro/vip/**", "roles[vip]"); // 指定loginurl 路徑 shiroFilterFactoryBean.setLoginUrl("/shiro/login"); // 登錄成功后跳轉(zhuǎn)路徑 shiroFilterFactoryBean.setSuccessUrl("/shiro/user/"); // for un authenticated shiroFilterFactoryBean.setUnauthorizedUrl("/shiro/unauth"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); // 自定義filters,可覆蓋默認(rèn)的Filter列表,參考 DefaultFilter Map<String, Filter> filters = new LinkedHashMap<String, Filter>(); // 定制logout 過濾,指定注銷后跳轉(zhuǎn)到登錄頁(默認(rèn)為根路徑) LogoutFilter logoutFilter = new LogoutFilter(); logoutFilter.setRedirectUrl("/shiro/login"); filters.put("logout", logoutFilter); // 定制authc 過濾,指定登錄表單參數(shù) FormAuthenticationFilter authFilter = new FormAuthenticationFilter(); authFilter.setUsernameParam("username"); authFilter.setPasswordParam("password"); filters.put("authc", authFilter); shiroFilterFactoryBean.setFilters(filters); return shiroFilterFactoryBean; } }
Test:登錄測試
package com.rz.monomer.modules.user.controller; import com.rz.monomer.commons.utils.Md5Encrypt; import lombok.extern.slf4j.Slf4j; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.*; import org.apache.shiro.authz.annotation.RequiresAuthentication; import org.apache.shiro.subject.Subject; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; @RestController @Slf4j public class LoginController { @PostMapping("/login") public String login(@RequestParam("username") String username, @RequestParam("password") String password) { Subject subject = SecurityUtils.getSubject(); AuthenticationToken token = new UsernamePasswordToken(username, Md5Encrypt.md5(password)); try { // 執(zhí)行登錄 subject.login(token); } catch (UnknownAccountException e) { // 未知用戶 log.warn("the account {} is not found", username); return "account not found"; } catch (IncorrectCredentialsException e) { // 用戶或密碼不正確 log.warn("the account or password is not correct"); return "account or password not correct"; } return "login success"; } }
補(bǔ)充:SpringBoot配置Shiro時踩坑
在SpringBoot2.0整合shiro時使用@EnableAutoConfiguration的時候需要對config文件進(jìn)行掃描,即使用@ComponentScan對配置進(jìn)行掃描。
或者直接使用@SpringBootApplication,但是這種方法會將主方法目錄下的所有package都進(jìn)行掃描影響項目效率。
Authentication failed for token submission [org.apache.shiro.authc.UsernamePasswordToken - zxc, rememberMe=false]. Possible unexpected error? (Typical or expected login exceptions should extend from AuthenticationException
當(dāng)出現(xiàn)此異常時,一般情況是用戶名密碼不匹配,或者是在配置對應(yīng)的Realm時出現(xiàn)空值導(dǎo)致匹配失敗。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。如有錯誤或未考慮完全的地方,望不吝賜教。
相關(guān)文章
Spring JdbcTemplate實現(xiàn)添加與查詢方法詳解
JdbcTemplate是Spring框架自帶的對JDBC操作的封裝,目的是提供統(tǒng)一的模板方法使對數(shù)據(jù)庫的操作更加方便、友好,效率也不錯,這篇文章主要介紹了Spring?JdbcTemplate執(zhí)行數(shù)據(jù)庫操作,需要的朋友可以參考下2022-11-11Spring boot整合shiro+jwt實現(xiàn)前后端分離
這篇文章主要為大家詳細(xì)介紹了Spring boot整合shiro+jwt實現(xiàn)前后端分離,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-12-12SpringBoot整合WebSocket實現(xiàn)后端向前端主動推送消息方式
這篇文章主要介紹了SpringBoot整合WebSocket實現(xiàn)后端向前端主動推送消息方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-10-10Spring Data Jpa 自動生成表結(jié)構(gòu)的方法示例
這篇文章主要介紹了Spring Data Jpa 自動生成表結(jié)構(gòu)的方法示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04