shiro概述
- Apache Shiro是Java的一個安全框架
- Shiro是一個強大的簡單易用的Java安全框架,主要用來更便捷的認證、授權、加密、會話管理、與Web集成、緩存等
- Shiro使用起來小而簡單
- spring中有spring security ,是一個權限框架,它和spring依賴過於緊密,沒有shiro使用簡單。
- shiro不依賴於spring,shiro不僅可以實現web應用的權限管理,還可以實現c/s系統,分布式系統權限管理,
- shiro屬於輕量框架,越來越多企業項目開始使用shiro.
shiro核心概念
- Authentication:身份認證/登錄,驗證用戶是不是擁有相應的身份;
- Authorization:授權,即權限驗證,驗證某個已認證的用戶是否擁有某個權限;
- Session Manager:會話管理,即用戶登錄后就是一次會話,在沒有退出之前,它的所有信息都在會話中;
- Cryptography:加密,保護數據的安全性
- Web Support:Web支持,可以非常容易的集成到Web環境;
- Caching:緩存,比如用戶登錄后,其用戶信息、擁有的角色/權限不必每次去查,這樣可以提高效率;
- Concurrency:shiro支持多線程應用的並發驗證,即如在一個線程中開啟另一個線程,能把權限自動傳播過去;
- Testing:提供測試支持;
- Run As:允許一個用戶假裝為另一個用戶(如果他們允許)的身份進行訪問;
- Remember Me:記住我,這個是非常常見的功能,即一次登錄后,下次再來的話不用登錄了。
主要概念
1. Subject 當前的操作用戶
- 可以是人 爬蟲 當前跟軟件交互的東西
- 在shiro當中我們可以統稱"用戶" 在代碼的任何地方,你都能輕易的獲得Shiro Subject。
- 一旦獲得Subject,你就可以立即獲得你希望用Shiro為當前用戶做的90%的事情 ,登錄、退、訪問會話、執行授權檢查等
2. SecurityManager
- SecurityManager則管理所有用戶的安全操作
- 引用了多個內部嵌套安全組件,是Shiro框架的核心
- 你可以把它看成DispatcherServlet前端控制器。
- 用於調度各種Shiro框架的服務
3. Realms
- Realms則是用戶的信息認證器和用戶的權限認證器
- 執行認證(登錄)和授權(訪問控制)時,Shiro會從應用配置的Realm中查找很多內容
- Realm 可以理解為讀取用戶信息、角色及權限的 DAO
- SecurityManager要驗證用戶身份與權限,那么它需要從Realm獲取相應的信息進行比較以確定用戶身份是否合法;
- 可以把Realm看成DataSource,即安全數據源。
4. Shiro架構
- subject:主體 主體可以是用戶也可以是程序,主體要訪問系統,系統需要對主體進行認證、授權。
- authenticator: 認證器 主體進行認證最終通過authenticator進行的。
- authorizer: 授權器 主體進行授權最終通過authenticator進行的。
- sessionManager:會話管理 web應用中一般是用web容器對session進行管理,shiro也提供一套session管理的方式。
- sessionDao: 通過sessionDao管理session數據,
- cacheManager: 緩存管理器 主要對session和授權數據進行緩存,比如將授權數據通過cacheManager進行緩存管理,和 ehcache整合對緩存數據進行管理。
- realm: 領域 相當於數據源,通過realm存取認證、授權相關數據。
- cryptography: 密碼管理 提供了一套加密/解密的組件,方便開發。比如 提供常用的散列、加/解密等功能。
Springboot整合shiro
-
新建一個springboot項目
-
導入springboot-web依賴
-
編寫controller和前端登錄頁面
需要整合thymeleaf 加入thymeleaf的依賴
<!--thymeleaf依賴-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>
4. 編寫前端頁面
在templates目錄下編寫 login.html,add.html,delete.html,index.html
導入thymeleaf的dtd
xmlns:th="http://www.thymeleaf.org"
login.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>登錄</title>
</head>
<body>
<form th:action="login">
<input type="text" name="username" value="">
<input type="password" name="password" value="">
<input type="submit" value="登錄">
</form>
</body>
</html>
index.html
add.html
delete.html
5. 編寫controller,跳轉到登錄頁面的方法
@RequestMapping({"/","tologin"})
public String tologin(){
return "login";
}
- 運行啟動 瀏覽器輸入localhost:8080
- 導入springboot整合shiro和mybatis連接數據庫的依賴
<!--shiro-整合spring的包-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.2</version>
</dependency>
<!--shiro整合thymeleaf-->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
- 創建數據庫 進行下一步的認證授權
##配置數據驅動信息 (key固定)
spring.datasource.driverClassName = com.mysql.jdbc.Driver
spring.datasource.url = jdbc:mysql:///spring_shiro
spring.datasource.username = root
spring.datasource.password =123456
在application.properties中添加數據庫信息
- 編寫mapper,service,pojo
pojo:
mapper:
service:
Impl:
controller:測試是否能夠查詢到
- 編寫shiroconfig配置類
- 編寫realm類 繼承AuthorizingRealm類 並實現方法
- 在shiroConfig中編寫代碼
@Configuration
public class shiroConfig {
//3. shiroFilterfactaryBean
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);//設置安全管理器
shiroFilterFactoryBean.setLoginUrl("/toLogin");//沒有認證后跳到的頁面
/**
* shiro的內置過濾器
anon:無需認證就可以訪問 默認
authc:必須認證了才能訪問
user:必須擁有記住我功能才能訪問
perms:必須擁有對某個的權限才能訪問
role:擁有某個角色權限才能訪問
*/
//添加shiro的內置過濾器 設置要攔截的url
Map<String,String> filterChainDefinitionMap=new LinkedHashMap<>();//攔截
filterChainDefinitionMap.put("/add","authc");// /add請求必須認證才能訪問
filterChainDefinitionMap.put("/del","authc");//del必須認證才能訪問
// filterChainDefinitionMap.put("user/**","authc");//支持通配符
//授權
filterChainDefinitionMap.put("/add","perms[user:add]");//沒有這個user:add權限的會被攔截下來
filterChainDefinitionMap.put("/del","perms[user:delete]");//沒有這個user:delete權限的會被攔截下來
//未授權的跳轉的url
shiroFilterFactoryBean.setUnauthorizedUrl("/Unauthorized");
//設置注銷的url
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);//把設置好的過濾設置到ShiroFilterFactoryBean
return shiroFilterFactoryBean;
}
//2. DefaultWebSecurityManager
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//關聯realm對象 userRealm
securityManager.setRealm(userRealm);
return securityManager;
}
//1. 創建realm對象 自定義的·類
@Bean
public UserRealm userRealm(){
return new UserRealm();
}
//整合shiroDialect:用來整合shiro-thymeleaf
@Bean
public ShiroDialect getshiroDialect(){
return new ShiroDialect();
}
}
- 在UserRealm編寫代碼
public class UserRealm extends AuthorizingRealm {
@Autowired
InfoService service;
//授權
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("執行了授權 doGetAuthorizationInfo");
SimpleAuthorizationInfo simpInfo = new SimpleAuthorizationInfo();
//獲取當前用戶的對象
Subject subject=SecurityUtils.getSubject();
Info user = (Info)subject.getPrincipal();//獲取用戶信息
simpInfo.addStringPermission(user.getPerm());//獲取數據庫權限
return simpInfo;
}
//認證
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("執行了認證 doGetAuthorizationInfo");
//獲取當前的用戶
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken userToken=(UsernamePasswordToken)authenticationToken;//獲取登錄的信息
//獲取用戶名 密碼 數據庫取
System.out.println(userToken.getUsername());
Info query = service.queryByName(userToken.getUsername());
System.out.println(query);
if(query==null){//沒有這個用戶
return null;
}
Session session=subject.getSession();//獲取用戶的session
session.setAttribute("loginuser",query);
if(!userToken.getUsername().equals(query.getUsername())){//判斷登錄的用戶名密碼 匹配數據庫是否正確
return null;//拋出異常
}
//密碼認證,shiro做
return new SimpleAuthenticationInfo(query,query.getPassword(),"");
}
}
14. 改寫controller
@RequestMapping("/login")
public String login(String username,String password){
try {
//獲取當前的用戶
Subject subject = SecurityUtils.getSubject();
//封裝用戶的登錄數據
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username, password);
subject.login(usernamePasswordToken);//執行登錄的方法 沒有異常就成功了
return "index";
} catch (UnknownAccountException e) {
/**
* 異常信息
* UnknownAccountException :用戶名不存在
* IncorrectCredentialsException:密碼錯誤
*/
e.printStackTrace();
System.out.println("用戶名不存在");
}catch (IncorrectCredentialsException e){
System.out.println("密碼錯誤");
}
return "login";
}
@RequestMapping("/add")
public String add(){//跳轉頁面
return "add";
}
@RequestMapping("/del")
public String delete(){//跳轉頁面
return "delete";
}
@RequestMapping("/Unauthorized")
public String Unauthorized(){//沒有權限跳轉的url
return "Unauthorized";
}
//注銷
@RequestMapping("/logout")
public String logout() {
Subject subject = SecurityUtils.getSubject();
Session session = subject.getSession();
session.setAttribute("loginuser",null);//清空session
return "login";
}
- 編寫未授權的頁面
Unauthorized.html
- 運行:
root用戶只有user:delete權限 所以只能看到刪除按鈕
dj用戶只有user:add權限 只能看到添加
ss用戶什么權限也沒有 所以什么按鈕也看不見
其中還有加密方式 比如md5 可以自行添加 就不一一介紹了
重點:shiroConfig類和UserRealm類配置好 核心**