Springboot整合shiro(簡單入門)
整合Shiro:
spring-boot 與 shiro整合的pom.xml檔案(一般都和資料庫聯用)
<!-- shiro整合spring的包-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-web-starter</artifactId>
< version>1.7.1</version>
</dependency>
<!-- mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</ dependency>
<!-- jdbc-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- JDBC驅動-->
<dependency>
<groupId>org.springframework.boot</ groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- 連線myal驅動-->
<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.2.4</version>
</dependency>
<!-- 匯入log4j-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
具體思想要檢視這個圖
Shiro的核心三個物件:
在這裡插入圖片描述
可以看到:應用程式碼直接互動的物件是 Subject,也就是說 Shiro 的對外 API 核心就是 Subject;其每個 API 的含義:
Subject:主體,代表了當前 “使用者”,這個使用者不一定是一個具體的人,與當前應用互動的任何東西都是 Subject,如網路爬蟲,機器人等;即一個抽象概念;所有 Subject 都繫結到 SecurityManager,與 Subject 的所有互動都會委託給 SecurityManager;可以把 Subject 認為是一個門面;SecurityManager 才是實際的執行者;
SecurityManager:安全管理器;即所有與安全有關的操作都會與 SecurityManager 互動;且它管理著所有 Subject;可以看出它是 Shiro 的核心,它負責與後邊介紹的其他元件進行互動,如果學習過 SpringMVC,你可以把它看成 DispatcherServlet 前端控制器;
Realm:域,Shiro 從從 Realm 獲取安全資料(如使用者、角色、許可權),就是說 SecurityManager 要驗證使用者身份,那麼它需要從 Realm 獲取相應的使用者進行比較以確定使用者身份是否合法;也需要從 Realm 得到使用者相應的角色 / 許可權進行驗證使用者是否能進行操作;可以把 Realm 看成 DataSource,即安全資料來源。
資料表(擁有perms許可權欄位):
注意:shiro中的配置類和Realm的實體類都是缺一不可的,一個是配置,注入到IOC容器中,另一個是處理和授權
和之前自定義的WebConfig一樣,建立要給ShiroConfig的配置類
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
@Bean
//ShiroFilterFactoryBean:3
public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//設定安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
//新增shiro的內建過濾器
/*
anon : 無需認證就可以訪問
authc: 必須認證了才能訪問
user: 必須擁有記住我 功能才能訪問
perms: 擁有對某個資源的許可權才能訪問
role: 擁有某個角色許可權才能訪問
*/
Map<String, String> filterMap = new LinkedHashMap<>();
//進行許可權的操作,正常情況下,沒有授權會跳轉到未授權的介面
//perms[user:add] : 必須是user使用者並且有add許可權才能執行這個/user/add操作
//perms[user:update]: 必須是user使用者並且有update許可權才能執行/user/update操作
filterMap.put("/user/add","perms[user:add]");
filterMap.put("/user/update","perms[user:update]");
//進行攔截的操作
//存放的為: 請求 + 認證
// filterMap.put("/user/add","authc");
// filterMap.put("/user/update","authc");
filterMap.put("/user/*","authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
//設定登入的請求
shiroFilterFactoryBean.setLoginUrl("/toLogin");
//設定未授權的頁面
shiroFilterFactoryBean.setUnauthorizedUrl("/noAuthorized");
return shiroFilterFactoryBean;
}
//DefaultWebSecurityManager:2
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//需要關聯Realm
securityManager.setRealm(userRealm);
return securityManager;
}
// 建立 realm物件,需要自定義:1
@Bean //這個userRealm,放入到IOC容器當中,方法名就是bean的名字
public UserRealm userRealm(){
return new UserRealm();
}
//整合ShiroDialect: 用來整合 shiro 與 thymeleaf
@Bean
public ShiroDialect getShiroDialect(){
return new ShiroDialect();
}
同時對於角色的授權和認證操作,都是Realm的實體類中(配合資料庫進行操作):
//自定義的userRealm extends AuthorizingRealm
public class UserRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
//授權
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("執行了=>授權doGetAuthorizationInfo");
//授權 :SimpleAuthorizationInfo
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//info.addStringPermission("user:add");
//拿到當前登入的這個物件
Subject subject = SecurityUtils.getSubject();
//拿到User物件
User currentUser = (User)subject.getPrincipal();
//設定當前的使用者
info.addStringPermission(currentUser.getPerms());
return info;
}
//認證
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("執行了=>認證doGetAuthenticationInfo");
//使用者名稱,密碼 --- 沒有,從資料庫中取得
// String name = "root";
// String password = "123456";
//這個token是全域性存在的,只要儲存下來了,就能夠獲得
UsernamePasswordToken userToken = (UsernamePasswordToken) token;
//從資料庫中獲得資料
//連線真實資料庫
User user = userService.queryUserByName(userToken.getUsername());
//如果使用者不存在
if(user == null){
return null; //自動丟擲異常 UnknownAccountException
}
//可以加密 : MD5鹽值加密
//密碼認證,shiro自動幫我們做, 加密了
return new SimpleAuthenticationInfo(user,user.getPwd(),"");
}
}