SpringBoot整合Shiro實(shí)現(xiàn)登錄認(rèn)證的方法
安全無(wú)處不在,趁著放假讀了一下 Shiro 文檔,并記錄一下 Shiro 整合 Spring Boot 在數(shù)據(jù)庫(kù)中根據(jù)角色控制訪問(wèn)權(quán)限
簡(jiǎn)介
Apache Shiro是一個(gè)功能強(qiáng)大、靈活的,開(kāi)源的安全框架。它可以干凈利落地處理身份驗(yàn)證、授權(quán)、企業(yè)會(huì)話管理和加密。
上圖是 Shiro 的基本架構(gòu)
Authentication(認(rèn)證)
有時(shí)被稱為“登錄”,用來(lái)證明用戶是用戶他們自己本人
Authorization(授權(quán))
訪問(wèn)控制的過(guò)程,即確定“誰(shuí)”訪問(wèn)“什么”
Session Management(會(huì)話管理)
管理用戶特定的會(huì)話,在 Shiro 里面可以發(fā)現(xiàn)所有的用戶的會(huì)話信息都會(huì)由 Shiro 來(lái)進(jìn)行控制
Cryptography(加密)
在對(duì)數(shù)據(jù)源使用加密算法加密的同時(shí),保證易于使用
Start
環(huán)境
Spring Boot 1.5.9 MySQL 5.7 Maven 3.5.2 Spring Data Jpa Lombok
添加依賴
這里只給出主要的 Shiro 依賴
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-starter</artifactId> <version>1.4.0-RC2</version> </dependency>
配置
我們暫時(shí)只需要用戶表、角色表,在 Spring boot 中修改配置文件將自動(dòng)為我們創(chuàng)建數(shù)據(jù)庫(kù)表
server: port: 8888 spring: datasource: driver-class-name: com.mysql.jdbc.Driver username: root password: root url: jdbc:mysql://localhost:3306/shiro?characterEncoding=utf-8&useSSL=false jpa: generate-ddl: true hibernate: ddl-auto: update show-sql: true
實(shí)體
Role.java
@Data @Entity public class Role { @Id @GeneratedValue private Integer id; private Long userId; private String role; }
User.java
@Data @Entity public class User { @Id @GeneratedValue private Long id; private String username; private String password; }
Realm
首先建立 Realm 類,繼承自 AuthorizingRealm,自定義我們自己的授權(quán)和認(rèn)證的方法。Realm 是可以訪問(wèn)特定于應(yīng)用程序的安全性數(shù)據(jù)(如用戶,角色和權(quán)限)的組件。
Realm.java
public class Realm extends AuthorizingRealm { @Autowired private UserService userService; //授權(quán) @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { //從憑證中獲得用戶名 String username = (String) SecurityUtils.getSubject().getPrincipal(); //根據(jù)用戶名查詢用戶對(duì)象 User user = userService.getUserByUserName(username); //查詢用戶擁有的角色 List<Role> list = roleService.findByUserId(user.getId()); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); for (Role role : list) { //賦予用戶角色 info.addStringPermission(role.getRole()); } return info; } //認(rèn)證 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { //獲得當(dāng)前用戶的用戶名 String username = (String) authenticationToken.getPrincipal(); //從數(shù)據(jù)庫(kù)中根據(jù)用戶名查找用戶 User user = userService.getUserByUserName(username); if (userService.getUserByUserName(username) == null) { throw new UnknownAccountException( "沒(méi)有在本系統(tǒng)中找到對(duì)應(yīng)的用戶信息。"); } SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(),getName()); return info; } }
Shiro 配置類
ShiroConfig.java
@Configuration public class ShiroConfig { @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>(); //以下是過(guò)濾鏈,按順序過(guò)濾,所以/**需要放最后 //開(kāi)放的靜態(tài)資源 filterChainDefinitionMap.put("/favicon.ico", "anon");//網(wǎng)站圖標(biāo) filterChainDefinitionMap.put("/**", "authc"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } @Bean public DefaultWebSecurityManager securityManager() { DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager(myRealm()); return defaultWebSecurityManager; } @Bean public MyRealm myRealm() { MyRealm myRealm = new MyRealm(); return myRealm; } }
控制器
UserController.java
@Controller public class UserController { @Autowired private UserService userService; @GetMapping("/") public String index() { return "index"; } @GetMapping("/login") public String toLogin() { return "login"; } @GetMapping("/admin") public String admin() { return "admin"; } @PostMapping("/login") public String doLogin(String username, String password) { UsernamePasswordToken token = new UsernamePasswordToken(username, password); Subject subject = SecurityUtils.getSubject(); try { subject.login(token); } catch (Exception e) { e.printStackTrace(); } return "redirect:admin"; } @GetMapping("/home") public String home() { Subject subject = SecurityUtils.getSubject(); try { subject.checkPermission("admin"); } catch (UnauthorizedException exception) { System.out.println("沒(méi)有足夠的權(quán)限"); } return "home"; } @GetMapping("/logout") public String logout() { return "index"; } }
Service
UserService.java
@Service public class UserService { @Autowired private UserDao userDao; public User getUserByUserName(String username) { return userDao.findByUsername(username); } @RequiresRoles("admin") public void send() { System.out.println("我現(xiàn)在擁有角色admin,可以執(zhí)行本條語(yǔ)句"); } }
展示層
admin.html
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <html lang="en"/> <head> <meta charset="UTF-8"/> <title>Title</title> </head> <body> <form action="/login" method="post"> <input type="text" name="username" /> <input type="password" name="password" /> <input type="submit" value="登錄" /> </form> </body> </html>
home.html
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <html lang="en"/> <head> <meta charset="UTF-8"/> <title>Title</title> </head> <body> home </body> </html>
index.html
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <html lang="en"/> <head> <meta charset="UTF-8"/> <title>Title</title> </head> <body> index <a href="/login" rel="external nofollow" >請(qǐng)登錄</a> </body> </html>
login.html
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <html lang="en"/> <head> <meta charset="UTF-8"/> <title>Title</title> </head> <body> <form action="/login" method="post"> <input type="text" name="username" /> <input type="password" name="password" /> <input type="submit" value="登錄" /> </form> </body> </html>
總結(jié)
這個(gè)小案例實(shí)現(xiàn)了根據(jù)角色來(lái)控制用戶訪問(wèn),其中最重要的就是 Realm,它充當(dāng)了Shiro與應(yīng)用安全數(shù)據(jù)間的“橋梁”或者“連接器”
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- SpringBoot+Shiro+Redis+Mybatis-plus 實(shí)戰(zhàn)項(xiàng)目及問(wèn)題小結(jié)
- 解決springboot+shiro 權(quán)限攔截失效的問(wèn)題
- Springboot和bootstrap實(shí)現(xiàn)shiro權(quán)限控制配置過(guò)程
- SpringBoot + Shiro前后端分離權(quán)限
- SpringBoot 整合 Shiro 密碼登錄與郵件驗(yàn)證碼登錄功能(多 Realm 認(rèn)證)
- Springboot shiro認(rèn)證授權(quán)實(shí)現(xiàn)原理及實(shí)例
- 基于springboot實(shí)現(xiàn)整合shiro實(shí)現(xiàn)登錄認(rèn)證以及授權(quán)過(guò)程解析
- Springboot+Shiro+Mybatis+mysql實(shí)現(xiàn)權(quán)限安全認(rèn)證的示例代碼
相關(guān)文章
Java使用單鏈表實(shí)現(xiàn)約瑟夫環(huán)
這篇文章主要為大家詳細(xì)介紹了Java使用單鏈表實(shí)現(xiàn)約瑟夫環(huán),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10Java數(shù)據(jù)結(jié)構(gòu)之優(yōu)先級(jí)隊(duì)列(堆)圖文詳解
優(yōu)先級(jí)隊(duì)列是比棧和隊(duì)列更專用的結(jié)構(gòu),在多數(shù)情況下都非常有用,下面這篇文章主要給大家介紹了關(guān)于Java數(shù)據(jù)結(jié)構(gòu)之優(yōu)先級(jí)隊(duì)列(堆)的相關(guān)資料,需要的朋友可以參考下2022-03-03java中instanceof 關(guān)鍵字作用和實(shí)際用途詳解
這篇文章主要介紹了java中instanceof 關(guān)鍵字作用和實(shí)際用途,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-04-04Spring Boot通過(guò)Redis實(shí)現(xiàn)防止重復(fù)提交
表單提交是一個(gè)非常常見(jiàn)的功能,如果不加控制,容易因?yàn)橛脩舻恼`操作或網(wǎng)絡(luò)延遲導(dǎo)致同一請(qǐng)求被發(fā)送多次,本文主要介紹了Spring Boot通過(guò)Redis實(shí)現(xiàn)防止重復(fù)提交,具有一定的參考價(jià)值,感興趣的可以了解一下2024-06-06Java Web監(jiān)聽(tīng)器如何實(shí)現(xiàn)定時(shí)發(fā)送郵件
這篇文章主要介紹了Java Web監(jiān)聽(tīng)器如何實(shí)現(xiàn)定時(shí)發(fā)送郵件,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-12-12springboot2+mybatis多種方式實(shí)現(xiàn)多數(shù)據(jù)配置方法
這篇文章主要介紹了springboot2+mybatis多種方式實(shí)現(xiàn)多數(shù)據(jù)配置方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03Spring中屬性注入的幾種方式以及復(fù)雜屬性的注入詳解
這篇文章主要介紹了Spring中屬性注入的幾種方式以及復(fù)雜屬性的注入詳解,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04Java獲取項(xiàng)目路徑方式System.getProperty(“user.dir“)
這篇文章主要介紹了Java獲取項(xiàng)目路徑方式System.getProperty(“user.dir“),具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-12-12