Shiro是一個強大的簡單易用的Java安全框架,主要用來更便捷的認證,授權,加密,會話管理。Shiro首要的和最重要的目標就是容易使用並且容易理解。
Shiro基本概念
三個核心組件:Subject, SecurityManager 和 Realms.
Subject
:翻譯爲主角,當前參與應用安全部分的主角。可以是用戶,可以試第三方服務,可以是cron 任務,或者任何東西。主要指一個正在與當前軟件交互的東西。所有Subject都需要SecurityManager,當你與Subject進行交互,這些交互行爲實際上被轉換爲與SecurityManager的交互
Subject代表了當前用戶的安全操作,SecurityManager則管理所有用戶的安全操作。
-
SecurityManager
:安全管理員,Shiro架構的核心,它就像Shiro內部所有原件的保護傘。然而一旦配置了SecurityManager,SecurityManager就用到的比較少,開發者大部分時間都花在Subject上面。
請記得,當你與Subject進行交互的時候,實際上是SecurityManager在背後幫你舉起Subject來做一些安全操作。 -
Realms
:Realms作爲Shiro和你的應用的連接橋,當需要與安全數據交互的時候,像用戶賬戶,或者訪問控制,Shiro就從一個或多個Realms中查找。Shiro提供了一些可以直接使用的Realms,如果默認的Realms不能滿足你的需求,你也可以定製自己的Realms
。
項目集成Shiro
導入POM
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>springboot-shiro-project</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-shiro-project</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--thymeleaf整合Shiro-->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
<!--整合lombok,讓代碼變得更簡潔-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
</dependency>
<!--整合MySQl和mybatis-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.18</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
<!--整合數據庫連接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.19</version>
</dependency>
<!--整合log4j日誌-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!--整合Shiro-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.1</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.1</version>
</dependency>
<!--整合swagger2-->
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<!---->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.11.RELEASE</version>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
<version>3.0.4.RELEASE</version>
</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>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
創建配置類
package com.example.springbootshiroproject.config;
@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//設置安全管理器
shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
Map<String,String> filterMap = new LinkedHashMap<>();
//授權,沒有授權會跳轉到未授權頁面
filterMap.put("/user/add","perms[user:add]");
filterMap.put("/user/update","perms[user:update]");
// filterMap.put("/user/add","authc");
filterMap.put("/user/*","authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
//設置登錄的請求
shiroFilterFactoryBean.setLoginUrl("/tologin");
//未授權,跳轉的頁面
shiroFilterFactoryBean.setUnauthorizedUrl("/noauth");
return shiroFilterFactoryBean;
}
//核心的安全事務管理器 getdefaultWebSecurityManager
@Bean(name = "securityManager")
public DefaultWebSecurityManager getdefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(userRealm);
return securityManager;
}
//UserRealm,這是個自定義的認證類,繼承自AuthorizingRealm,負責用戶的認證和權限的處理
@Bean
public UserRealm userRealm(){
return new UserRealm();
}
//整合shiro和thyemleaf
@Bean
public ShiroDialect getShiroDialect(){
return new ShiroDialect();
}
}
package com.example.springbootshiroproject.config;
//UserRealm,這是個自定義的認證類,繼承自AuthorizingRealm,負責用戶的認證和權限的處理
public class UserRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
//授權
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("執行了授權:doGetAuthorizationInfo");
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addStringPermission("user:add");
//獲取當前登錄的對象
Subject subject = SecurityUtils.getSubject();
User currentUser = (User) subject.getPrincipal();
info.addStringPermission(currentUser.getPerms());
System.out.println(info);
return info;
}
//認證
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("執行了認證:doGetAuthenticationInfo");
UsernamePasswordToken userToken = (UsernamePasswordToken) token;
User user = userService.queryUserByName(userToken.getUsername());
if(user==null){
return null;
}
//密碼認證 shiro 來做
return new SimpleAuthenticationInfo(user,user.getPwd(),"");
}
}
控制層代碼
package com.example.springbootshiroproject.controller;
@Controller
public class HelloController {
@GetMapping("/index")
public String toIndex(Model model){
model.addAttribute("msg","hello shiro");
return "index";
}
@PostMapping("/user/add")
public String add(){
return "/user/add";
}
@PostMapping("/user/update")
public String update(){
return "/user/update";
}
@GetMapping("/tologin")
public String login(){
return "login";
}
@PostMapping("/login")
public String login(String username,String password,Model model){
//獲取當前用戶
Subject subject = SecurityUtils.getSubject();
//封裝用戶的登錄數據
UsernamePasswordToken token = new UsernamePasswordToken(username,password);
try {
subject.login(token);//執行登錄的方法
return "index";
} catch (UnknownAccountException e) {
model.addAttribute("msg","用戶名錯誤");
return "login";
}catch (IncorrectCredentialsException e){
model.addAttribute("msg","密碼錯誤");
return "login";
}
}
@GetMapping("/noauth")
@ResponseBody
public String unauthorized(){
return "未經授權,不能訪問此頁面";
}
}
- 到這兒,與Shiro相關的代碼已經結束了。所以代碼不在列出。完成代碼請查看github自行下載,代碼都是自己寫的,也都親自跑過,可放心使用。
- github:https://github.com/carroll1118/Shiro-Spring-Security.git
你知道的越多,你不知道的越多。
有道無術,術尚可求,有術無道,止於術。
如有其它問題,歡迎大家留言,我們一起討論,一起學習,一起進步