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.測試
到此啟動項目,登入測試即可
最後項目的目錄結構如下: