Springboot整合Shiro之認證
- 2019 年 12 月 2 日
- 筆記
版權聲明:本文為部落客原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
本文鏈接:https://dpb-bobokaoya-sm.blog.csdn.net/article/details/103322744
Shiro
是我們常用的一個許可權管理框架,我們之前已經詳細的給大家介紹過了Shiro的基礎知識,不太清楚的可以參考下 https://blog.csdn.net/qq_38526573/category_9284714.html 此文,本文的重點是來介紹下在SpringBoot環境下我們怎麼來使用Shiro。
一、添加相關依賴
本案例中我們使用SpringDataJPA
和Thymeleaf
來配合講解,所以相關的依賴如下
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.3.2</version> </dependency> <!-- springBoot的啟動器 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <!-- mysql --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <!-- druid連接池 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.0.9</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> </dependencies>
二、添加相關的配置資訊
在application.properties中添加如下的配置資訊
# jdbc 的相關資訊 spring.datasource.driverClassName=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/srm?characterEncoding=utf-8 spring.datasource.username=root spring.datasource.password=123456 # 配置連接池資訊 spring.datasource.type=com.alibaba.druid.pool.DruidDataSource # 配置jpa的相關參數 spring.jpa.hibernate.ddl-auto=update spring.jpa.show-sql=true
三、業務準備
我們提前將登錄認證的後台業務先完成。我們提前將登錄認證的後台業務先完成。
1.對應的表結構
CREATE TABLE `t_user` ( `id` int(20) NOT NULL AUTO_INCREMENT, `username` varchar(20) DEFAULT NULL, `password` varchar(100) DEFAULT NULL, `salt` varchar(100) DEFAULT NULL, `create_time` datetime DEFAULT NULL, `state` int(1) DEFAULT NULL, `last_login_time` datetime DEFAULT NULL, `nickname` varchar(30) DEFAULT NULL, `realname` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
2.pojo對象
package com.dpb.springboot41shiro.pojo; import javax.persistence.*; /** * @program: springboot-41-shiro * @description: * @author: 波波烤鴨 * @create: 2019-11-29 20:06 */ @Entity @Table(name = "t_user") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private Integer id; @Column(name = "username") private String username; @Column(name = "password") private String password; @Column(name = "salt") private String salt; @Column(name = "realname") private String realname; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getSalt() { return salt; } public void setSalt(String salt) { this.salt = salt; } public String getRealname() { return realname; } public void setRealname(String realname) { this.realname = realname; } }
3.dao介面
介面我們通過 JpaRepository介面來實現,然後根據名稱規則來定義方法
public interface UserDao extends JpaRepository<User,Integer> { /** * 根據帳號查詢 * @param username * @return */ List<User> findByUsername(String username); }
4.業務層程式碼
業務層就實現簡單的調用即可
四、Shiro整合
接下來我們就可以來整合Shiro框架了
1.自定義Realm文件
首先我們定義一個realm實現類來實現我們認證和授權的邏輯
package com.dpb.springboot41shiro.realm; import com.dpb.springboot41shiro.pojo.User; import com.dpb.springboot41shiro.service.UserService; import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.util.SimpleByteSource; import org.springframework.beans.factory.annotation.Autowired; import java.util.List; /** * @program: springboot-41-shiro * @description: 自定義Realm * @author: 波波烤鴨 * @create: 2019-11-29 19:37 */ public class AuthcRealm extends AuthorizingRealm { /** * 認證的方法 * @param authenticationToken * @return * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { return null; } /** * 授權的方法 * @param principalCollection * @return */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { return null; } }
邏輯可以稍後實現
2.Shiro的配置類
我們先來看下之前在spring整合shiro的時候,我們的整合配置文件:
那麼我們在SpringBoot中只需將此配置轉換為對應的java配置即可,如下
package com.dpb.springboot41shiro.config; import com.dpb.springboot41shiro.realm.AuthcRealm; import org.apache.shiro.authc.credential.HashedCredentialsMatcher; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.HashMap; import java.util.Map; /** * @program: springboot-41-shiro * @description: Shiro的配置類 * @author: 波波烤鴨 * @create: 2019-11-29 19:31 */ @Configuration public class ShiroConfig { @Value("${shiro.hashAlgorithmName}") private String hashAlgorithmName; @Value("${shiro.hashIterations}") private Integer hashIterations; /** * 獲取憑證匹配器 * @return */ @Bean public HashedCredentialsMatcher hashedCredentialsMatcher(){ HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(); matcher.setHashAlgorithmName(hashAlgorithmName); matcher.setHashIterations(hashIterations); return matcher; } /** * 獲取自定義的Realm * @return */ @Bean public AuthcRealm authcRealm(){ AuthcRealm realm = new AuthcRealm(); realm.setCredentialsMatcher(hashedCredentialsMatcher()); return realm; } /** * 獲取SecurityManager對象 * @return */ @Bean public SecurityManager securityManager(){ DefaultWebSecurityManager manager = new DefaultWebSecurityManager(); manager.setRealm(authcRealm()); return manager; } /** * 註冊ShiroFilterFactoryBean * @return */ @Bean(name = "shiroFilter") public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager manager){ ShiroFilterFactoryBean filter = new ShiroFilterFactoryBean(); filter.setSecurityManager(manager); filter.setLoginUrl("/login.do"); filter.setSuccessUrl("/success.html"); filter.setUnauthorizedUrl("/refuse.html"); // 設置過濾器 Map<String,String> map = new HashMap<>(); map.put("/css/**","anon"); map.put("/img/**","anon"); map.put("/js/**","anon"); map.put("/login","anon"); map.put("/login.do","authc"); map.put("/**","authc"); filter.setFilterChainDefinitionMap(map); return filter; } }
3.訪問測試
到此shiro已經被集成到了我們項目中,我們可以根據我們配置的過濾鏈路來啟動訪問下,首先創建如下的相關文件,便於測試
同時添加對應的跳轉控制器
/** * @program: springboot-41-shiro * @description: 基礎控制器 * @author: 波波烤鴨 * @create: 2019-11-29 19:52 */ @Controller public class BaseController { @RequestMapping("/{path}") public String page(@PathVariable String path){ return path; } }
訪問需要認證的success.html ,會給錯誤提示 訪問img/a2.jpg可以直接訪問
五、登錄認證測試
接下來我們實現下認證的過程。
1.自定義realm實現登錄
自定義realm認證的流程如下
@Autowired private UserService service; /** * 認證的方法 * @param authenticationToken * @return * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; String userName = token.getUsername(); System.out.println("開始登錄認證:"+userName); List<User> list = service.login(userName); if (list == null || list.size() != 1) { return null; } User user = list.get(0); return new SimpleAuthenticationInfo(user,user.getPassword(),new SimpleByteSource(user.getSalt()),"authcRealme"); }
2.創建登錄表單
前端我們用Thymeleaf來作為模組框架,創建登錄表單
<!DOCTYPE html> <html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" > <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>登錄管理</h1> <form th:action="@{/login.do}" method="post"> 帳號:<input type="text" name="username"><br> 密碼:<input type="text" name="password"><br> <input type="submit" value="登錄"> </form> </body> </html>
3.創建認證的控制器
同時我們創建認證的控制器,來處理認證失敗的情況
package com.dpb.springboot41shiro.controller; import org.apache.shiro.SecurityUtils; import org.apache.shiro.crypto.hash.Md5Hash; import org.apache.shiro.web.filter.authc.FormAuthenticationFilter; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import javax.servlet.http.HttpServletRequest; /** * @program: springboot-41-shiro * @description: 認證的控制器 * @author: 波波烤鴨 * @create: 2019-11-29 20:12 */ @Controller public class AuthcController { @RequestMapping("/login.do") public String login(HttpServletRequest request){ Object obj = request.getAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME); System.out.println("認證的錯誤資訊:" + obj); return "/login"; } /** * 註銷的方法 * @return */ @RequestMapping("/logout.do") public String logout(){ SecurityUtils.getSubject().logout(); return "redirect:/login"; } }
4.準備數據
我們可以自己通過Md5加密一個密碼然後保存到資料庫中
5.測試
到此啟動項目,登錄測試即可
最後項目的目錄結構如下: