SpringBoot淺析安全管理之Shiro框架
Shiro 簡(jiǎn)介
Apache Shiro 是一個(gè)開源的輕量級(jí)的 Java 安全框架,它提供身份驗(yàn)證、授權(quán)、密碼管理以及會(huì)話管理等功能。相對(duì)于 Spring Security ,Shiro 框架更加直觀、易用,同時(shí)也能提供健壯的安全性。
在傳統(tǒng)的 SSM 框架中,手動(dòng)整合 Shiro 的配置步驟還是比較多的,針對(duì) Spring Boot ,Shiro 官方提供了 shiro-spring-boot-web-starter 用來(lái)簡(jiǎn)化 Shiro 在 Spring Boot 中的配置。
整合 Shiro
1. 創(chuàng)建項(xiàng)目
首先創(chuàng)建一個(gè)普通的 Spring Boot Web 項(xiàng)目,添加 Shiro 依賴以及頁(yè)面模板依賴
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-web-starter</artifactId> <version>1.4.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>com.github.theborakompanioni</groupId> <artifactId>thymeleaf-extras-shiro</artifactId> <version>2.0.0</version> </dependency>
這里不需要添加 spring-boot-starter-web 依賴,shiro-spring-boot-web-starter 中已經(jīng)依賴了 spring-boot-starter-web 。同時(shí),此處使用 Thymeleaf 模板,為了在 Thymeleaf 使用 shiro 標(biāo)簽,加入了 thymeleaf-extras-shiro 依賴。
2. Shiro基本配置
在 application.properties 中配置 Shiro 的基本信息
# 開啟 Shiro 配置,默認(rèn)為 true
shiro.enabled=true
# 開啟 Shiro Web 配置,默認(rèn)為 true
shiro.web.enabled=true
# 配置登錄地址,默認(rèn)為 /login.jsp
shiro.loginUrl=/login
# 配置登錄成功的地址,默認(rèn)為 /
shiro.successUrl=/index
# 未獲授權(quán)默認(rèn)跳轉(zhuǎn)地址
shiro.unauthorizedUrl=/unauthorized
# 是否允許通過(guò) URL 參數(shù)實(shí)現(xiàn)會(huì)話跟蹤,如果網(wǎng)站支持 Cookie,可以關(guān)閉此選項(xiàng),默認(rèn)為 true
shiro.sessionManager.sessionIdUrlRewritingEnabled=true
# 是否允許通過(guò) Cookie 實(shí)現(xiàn)會(huì)話跟蹤,默認(rèn)為 true
shiro.sessionManager.sessionIdCookieEnabled=true
然后在 Java 代碼中配置 Shiro ,提供兩個(gè)最基本的 Bean 即可
@Configuration public class ShiroConfig { @Bean public Realm realm() { TextConfigurationRealm realm = new TextConfigurationRealm(); realm.setUserDefinitions("sang=123,user\n admin=123,admin"); realm.setRoleDefinitions("admin=read,write\n user=read"); return realm; } @Bean public ShiroFilterChainDefinition shiroFilterChainDefinition() { DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition(); chainDefinition.addPathDefinition("/login", "anon"); chainDefinition.addPathDefinition("/doLogin", "anon"); chainDefinition.addPathDefinition("/logout", "logout"); chainDefinition.addPathDefinition("/**", "authc"); return chainDefinition; } @Bean public ShiroDialect shiroDialect() { return new ShiroDialect(); } }
代碼解釋:
- 這里提供兩個(gè)關(guān)鍵的 Bean ,一個(gè)是 Realm,另一個(gè)是 ShiroFilterChainDefinition 。至于 ShiroDialect 則是為了支持在 Thymeleaf 中使用 Shiro 標(biāo)簽,如果不在 Thymeleaf 中使用 Shiro 標(biāo)簽,那么可以不提供 ShiroDialect
- Realm 可以是自定義的 Realm,也可以是 Shiro 提供的 Realm,簡(jiǎn)單起見,此處沒(méi)有配置數(shù)據(jù)庫(kù)連接,直接配置了兩個(gè)用戶:sang/123 和 admin/123 ,分別對(duì)應(yīng)角色 user 和 admin。
- ShiroFilterChainDefinition Bean 中配置了基本的過(guò)濾規(guī)則 ,“/login” 和 “/doLogin”,可以匿名訪問(wèn),“/logout”是一個(gè)注銷登錄請(qǐng)求,其余請(qǐng)求則都需要認(rèn)證后才能訪問(wèn)
然后配置登錄接口以及頁(yè)面訪問(wèn)接口
@Controller public class UserController { @PostMapping("/doLogin") public String doLogin(String username, String password, Model model) { UsernamePasswordToken token = new UsernamePasswordToken(username, password); Subject subject = SecurityUtils.getSubject(); try { subject.login(token); } catch (AuthenticationException e) { model.addAttribute("error", "用戶名或密碼輸入錯(cuò)誤!"); return "login"; } return "redirect:/index"; } @RequiresRoles("admin") @GetMapping("/admin") public String admin() { return "admin"; } @RequiresRoles(value = {"admin", "user"}, logical = Logical.OR) @GetMapping("/user") public String user() { return "user"; } }
代碼解釋:
- 在 doLogin 方法中,首先構(gòu)建一個(gè) UsernamePasswordToken 實(shí)例,然后獲取一個(gè) Subject 對(duì)象并調(diào)用該對(duì)象中的 login 方法執(zhí)行登錄操作,在登錄操作執(zhí)行過(guò)程中,當(dāng)有異常拋出時(shí),說(shuō)明登錄失敗,攜帶錯(cuò)誤信息返回登錄視圖;當(dāng)?shù)卿洺晒r(shí),則重定向到“/index”
- 接下來(lái)暴露兩個(gè)接口“/admin”和“/user”,對(duì)于“/admin”接口,需要具有 admin 角色才可以訪問(wèn);對(duì)于“/user”接口,具備 admin 角色 和 user角色其中任意一個(gè)即可訪問(wèn)
對(duì)于其他不需要角色就能訪問(wèn)的接口,直接在 WebMvc 中配置即可
@Configuration public class WebMvcConfig implements WebMvcConfigurer{ @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/login").setViewName("login"); registry.addViewController("/index").setViewName("index"); registry.addViewController("/unauthorized").setViewName("unauthorized"); } }
接下來(lái)創(chuàng)建全局異常處理器進(jìn)行全局異常處理,此處主要是處理授權(quán)異常
@ControllerAdvice public class ExceptionController { @ExceptionHandler(AuthorizationException.class) public ModelAndView error(AuthorizationException e) { ModelAndView mv = new ModelAndView("unauthorized"); mv.addObject("error", e.getMessage()); return mv; } }
當(dāng)用戶訪問(wèn)未授權(quán)的資源時(shí),跳轉(zhuǎn)到 unauthorized 視圖中,并攜帶出錯(cuò)誤信息。
配置完成后,最后在 resources/templates 目錄下創(chuàng)建 5 個(gè) HTML 頁(yè)面進(jìn)行測(cè)試。
(1)index.html
<!DOCTYPE html> <html lang="en" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>Hello, <shiro:principal/></h3> <h3><a href="/logout" rel="external nofollow" >注銷登錄</a></h3> <h3><a shiro:hasRole="admin" href="/admin" rel="external nofollow" >管理員頁(yè)面</a></h3> <h3><a shiro:hasAnyRoles="admin,user" href="/user" rel="external nofollow" >普通用戶頁(yè)面</a></h3> </body> </html>
(2)login.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div> <form action="/doLogin" method="post"> <input type="text" name="username"><br> <input type="password" name="password"><br> <div th:text="${error}"></div> <input type="submit" value="登錄"> </form> </div> </body> </html>
(3)user.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>普通用戶頁(yè)面</h1> </body> </html>
(4)admin.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>管理員頁(yè)面</h1> </body> </html>
(5)unauthorized.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div> <h3>未獲授權(quán),非法訪問(wèn)</h3> <h3 th:text="${error}"></h3> </div> </body> </html>
3. 測(cè)試
啟動(dòng)項(xiàng)目,訪問(wèn)登錄頁(yè)面,使用 sang/123 登錄
注意:由于 sang 用戶不具備 admin 角色,因此登錄成功后的頁(yè)面沒(méi)有前往管理員頁(yè)面的超鏈接。
然后使用 admin/123 登錄。
如果用戶使用 sang 登錄,然后去訪問(wèn):http://localhost:8080/admin,會(huì)跳轉(zhuǎn)到未授權(quán)頁(yè)面
以上通過(guò)一個(gè)簡(jiǎn)單的案例展示了如何在 Spring Boot 中整合 Shiro 以及如何在 Thymeleaf 中使用 Shiro 標(biāo)簽,一旦整合成功,接下來(lái) Shiro 的用法就和原來(lái)的一模一樣。此處主要將 Spring Boot 整合 Shiro,對(duì)于 Shiro 的其它用法,可以參考 Shiro 官方文檔。
到此這篇關(guān)于SpringBoot淺析安全管理之Shiro框架的文章就介紹到這了,更多相關(guān)SpringBoot Shiro框架內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
spring data jpa如何只查詢實(shí)體部分字段
這篇文章主要介紹了spring data jpa如何只查詢實(shí)體部分字段的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06spring boot2.0實(shí)現(xiàn)優(yōu)雅停機(jī)的方法
這篇文章主要介紹了spring boot2.0實(shí)現(xiàn)優(yōu)雅停機(jī)的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-05-05全面了解OAuth?2.0四種授權(quán)方式金三銀四無(wú)懼面試
這篇文章主要介紹了全面了解OAuth?2.0四種授權(quán)方式金三銀四無(wú)懼面試,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02Java編寫計(jì)算器的常見方法實(shí)例總結(jié)
這篇文章主要介紹了Java編寫計(jì)算器的常見方法,結(jié)合實(shí)例形式總結(jié)分析了Java實(shí)現(xiàn)計(jì)算器功能的常用方法,需要的朋友可以參考下2016-04-04SpringBoot集成MyBatis的分頁(yè)插件PageHelper實(shí)例代碼
這篇文章主要介紹了SpringBoot集成MyBatis的分頁(yè)插件PageHelper的相關(guān)操作,需要的朋友可以參考下2017-08-08Springboot項(xiàng)目監(jiān)聽器失效問(wèn)題解決
這篇文章主要介紹了Springboot項(xiàng)目監(jiān)聽器失效問(wèn)題解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03java的Array,List和byte[],String相互轉(zhuǎn)換的方法你了解嘛
這篇文章主要為大家詳細(xì)介紹了java的Array,List和byte[],String相互轉(zhuǎn)換的方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助2022-02-02SpringBoot Actuator潛在的OOM問(wèn)題的解決
本文主要介紹了SpringBoot Actuator潛在的OOM問(wèn)題的解決,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-11-11