Shiro 簡介
Apache Shiro 是一個(gè)開源的輕量級的 Java 安全框架,它提供身份驗(yàn)證、授權(quán)、密碼管理以及會話管理等功能。相對於 Spring Security ,Shiro 框架更加直覺、易用,同時(shí)也能提供健壯的安全性。
在傳統(tǒng)的SSM 框架中,手動整合Shiro 的配置步驟還是比較多的,針對Spring Boot ,Shiro 官方提供了shiro-spring-boot-web-starter 用來簡化Shiro 在Spring Boot 中的配置。
整合Shiro
1. 建立項(xiàng)目
首先建立一個(gè)普通的Spring Boot Web 項(xiàng)目,加入Shiro 依賴以及頁面模板依賴
<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 配置,預(yù)設(shè)為true
shiro.enabled =true
# 開啟Shiro Web 配置,預(yù)設(shè)為true
shiro.web.enabled=true
# 設(shè)定登入位址,預(yù)設(shè)為/login.jsp
shiro.loginUrl=/login
# 配置登入成功的位址,預(yù)設(shè)為/
shiro.successUrl=/index
# 未獲授權(quán)預(yù)設(shè)跳轉(zhuǎn)位址
shiro.unauthorizedUrl=/unauthorized
# 是否允許透過URL 參數(shù)實(shí)現(xiàn)會話跟蹤,如果網(wǎng)站支援Cookie,可以關(guān)閉此選項(xiàng),預(yù)設(shè)為true
shiro.sessionManager.sessionIdUrlRewritingEnabled=true
# 是否允許透過Cookie 實(shí)現(xiàn)會話跟蹤,預(yù)設(shè)為true
shiro.sessionManager.sessionIdCookieEnabled=true
然後在Java 程式碼中設(shè)定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,簡單起見,此處沒有配置資料庫連接,直接配置了兩個(gè)使用者:sang/123 和admin/123 ,分別對應(yīng)角色user 和admin。
ShiroFilterChainDefinition Bean 中配置了基本的過濾規(guī)則,“/login” 和“/doLogin”,可以匿名訪問,“/logout”是一個(gè)註銷登錄請求,其餘請求則都需要認(rè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è)UsernamePasswordToken 實(shí)例,然後取得一個(gè)Subject 物件並呼叫該物件中的login 方法執(zhí)行登入操作,在登入操作執(zhí)行過程中,當(dāng)有異常拋出時(shí),說明登入失敗,攜帶錯(cuò)誤訊息返回登入視圖;當(dāng)?shù)侨氤晒r(shí),則重定向到“/index”
- 接下來暴露兩個(gè)接口“/admin”和“/user”,對於“/admin”接口,需要具有admin 角色才可以存取;對於「/user」接口,具備admin 角色和user角色其中任何一個(gè)即可訪問
對於其他不需要角色就能訪問的接口,直接在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");
}
}
接下來建立全域異常處理器進(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)使用者存取未授權(quán)的資源時(shí),跳到unauthorized 檢視中,並攜帶出錯(cuò)誤訊息。
設(shè)定完成後,最後在 resources/templates 目錄下建立 5 個(gè) HTML 頁面進(jìn)行測試。
(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>
<h4>Hello, <shiro:principal/></h4>
<h4><a href="/logout" rel="external nofollow" >注銷登錄</a></h4>
<h4><a shiro:hasRole="admin" href="/admin" rel="external nofollow" >管理員頁面</a></h4>
<h4><a shiro:hasAnyRoles="admin,user" href="/user" rel="external nofollow" >普通用戶頁面</a></h4>
</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>
<h2>普通用戶頁面</h2>
</body>
</html>
(4)admin. html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h2>管理員頁面</h2>
</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>
<h4>未獲授權(quán),非法訪問</h4>
<h4 th:text="${error}"></h4>
</div>
</body>
</html>
3. 測試
啟動項(xiàng)目,造訪登入頁面,使用sang/123 登入

#注意:由於sang 使用者不具備admin 角色,因此登入成功後的頁面沒有前往管理員頁面的超連結(jié)。
然後使用 admin/123 登入。

如果使用者使用sang 登錄,然後去存?。篽ttp://localhost:8080/admin,會跳到未授權(quán)頁面

以上是SpringBoot安全管理之Shiro框架怎麼使用的詳細(xì)內(nèi)容。更多資訊請關(guān)注PHP中文網(wǎng)其他相關(guān)文章!