文章目錄
1. 環境的基本搭建
這裏的類似什麼啓動類,頁面跳轉的之間的代碼這裏我就省略啦,直接寫shiro的配置類.如果對詳細信息想了解的話,請參考代碼連接,項目的下載地址爲:
鏈接:https://pan.baidu.com/s/1Rxubu_XgDoehuAc0uESyaQ
提取碼:2kau
1.項目依賴
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.tvu</groupId>
<artifactId>SpringBoot-Shrio</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 繼承Spring Boot的默認父工程 -->
<!-- Spring Boot 父工程 -->
<properties>
<!-- 修改JDK的編譯版本爲1.8 -->
<java.version>1.8</java.version>
<!-- 修改thymeleaf的版本 -->
<thymeleaf.version>3.0.2.RELEASE</thymeleaf.version>
<thymeleaf-layout-dialect.version>2.0.4</thymeleaf-layout-dialect.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.4.RELEASE</version>
</parent>
<dependencies>
<!-- 導入web支持:SpringMVC開發支持,Servlet相關的程序 -->
<!-- web支持,SpringMVC, Servlet支持等 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
</dependencies>
</project>
2.配置類
基礎的配置類
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.HashMap;
@Configuration
public class ShiroConfig {
/**
* 創建ShiroFilterFactoryBean
*/
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
return shiroFilterFactoryBean;
}
/**
* 創建DefaultWebSecurityManager
*/
@Bean(name="securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm")UserRealm userRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(userRealm);
return securityManager;
}
/**
* 創建Realm
*/
@Bean(name="userRealm")
public UserRealm getRealm(){
return new UserRealm();
}
}
簡單的基礎邏輯
package com.bwie.shrio;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
public class UserRealm extends AuthorizingRealm {
/**
* 執行授權邏輯
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
System.out.println("執行授權邏輯");
return null;
}
/**
* 執行認證邏輯
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {
System.out.println("執行認證邏輯");
return null;
}
}
2. 資源權限的攔截
Shiro 自帶很多的攔截器,比如常用的過濾器
annon 無需登錄,可以訪問
authc:必須認證纔可以訪問
user:如果使用remberme的功能 可以直接訪問
perms:該資源必須授權
role:該資源必須得到角色權限纔可以訪問
需求1:當我訪問add或者update的時候,需要進行登錄
@Configuration
public class ShiroConfig {
/**
* 創建ShiroFilterFactoryBean
*/
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
HashMap<String, String> filterMap = new HashMap<>();
filterMap.put("/addOrder","authc");
filterMap.put("/updateOrder","authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactoryBean;
}
/**
* 創建DefaultWebSecurityManager
*/
@Bean(name="securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm")UserRealm userRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(userRealm);
return securityManager;
}
/**
* 創建Realm
*/
@Bean(name="userRealm")
public UserRealm getRealm(){
return new UserRealm();
}
}
實現後大致效果如下
3. 自定義跳轉頁面
/**
* 創建ShiroFilterFactoryBean
*/
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
/**
* 常用的過濾器:annon 無需登錄,可以訪問
* authc:必須認證纔可以訪問
* user:如果使用remberme的功能 可以直接訪問
* perms:該資源必須授權
* role:該資源必須得到角色權限纔可以訪問
*/
HashMap<String, String> filterMap = new HashMap<>();
filterMap.put("/addOrder","authc");
filterMap.put("/updateOrder","authc");
shiroFilterFactoryBean.setLoginUrl("/login"); -----> 跳轉頁面
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactoryBean;
}
4. 用戶登錄的驗證
前臺
<body>
<h3 th:text="${msg}" style="color: red"></h3>
<h1>權限控制登陸系統</h1>
<form action="/tologin" method="get">
<!--username,username 不更改名字-->
<span>用戶名稱</span><input type="text" name="username" /> <br>
<span>用戶密碼</span><input type="password" name="password" /> <br>
<input type="submit" value="登陸">
</form>
</body>
</html>
後臺controller
// 自定義登陸頁面
@GetMapping("/tologin")
public String login(String username, String password, Model model) {
//獲取subject
Subject subject = SecurityUtils.getSubject();
//封裝用戶數據
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
//執行登錄方法
try {
subject.login(token);
return "main";
} catch (UnknownAccountException e) {
model.addAttribute("msg", "用戶名不存在");
return "login";
} catch (IncorrectCredentialsException e) {
model.addAttribute("msg", "密碼錯誤");
return "login";
}
}
後臺認證邏輯
/**
* 執行認證邏輯
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("執行認證邏輯");
String name = "admin";
String password = "123";
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
if (!token.getUsername().equals(name)){
//用戶名不存在
return null; //底層會拋出用戶名不存在異常
}
if (!token.getUsername().equals(name)){
//用戶名不存在
return null; //底層會拋出用戶名不存在異常
}
//判斷密碼
return new SimpleAuthenticationInfo("",password,""); //判斷密碼 我們交給框架去執行
}
對tologin頁面不進行攔截.放行他
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
/**
* 常用的過濾器:anon 無需登錄,可以訪問
* authc:必須認證纔可以訪問
* user:如果使用remberme的功能 可以直接訪問
* perms:該資源必須授權
* role:該資源必須得到角色權限纔可以訪問
*/
HashMap<String, String> filterMap = new HashMap<>();
filterMap.put("/addOrder","authc");
filterMap.put("/updateOrder","authc");
filterMap.put("/tologin","anon"); //-->>放行
shiroFilterFactoryBean.setLoginUrl("/login");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactoryBean;
}
當代用 Subject subject = SecurityUtils.getSubject();時,其實走的邏輯的就是AuthenticationInfo 的設定的邏輯
5. 整合mybaties用戶登錄的驗證
1.添加依賴
<!-- 導入mybatis相關的依賴 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.9</version>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- SpringBoot的Mybatis啓動器 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
2. 配置application.properties
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
mybatis.type-aliases-package=com.itheima.domain
4.編寫實體類
package com.itheima.domain;
public class User {
private Integer id;
private String name;
private String password;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
3.編寫mapper
package com.itheima.mapper;
import com.itheima.domain.User;
public interface UserMapper {
public User findByName(String name);
}
4.編寫實現類
package com.itheima.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.itheima.domain.User;
import com.itheima.mapper.UserMapper;
import com.itheima.service.UserService;
@Service
public class UserServiceImpl implements UserService{
//注入Mapper接口
@Autowired
private UserMapper userMapper;
@Override
public User findByName(String name) {
return userMapper.findByName(name);
}
}
5.編寫xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 該文件存放CRUD的sql語句 -->
<mapper namespace="com.itheima.mapper.UserMapper">
<select id="findByName" parameterType="string" resultType="user">
SELECT id,
NAME,
PASSWORD
FROM
user where name = #{value}
</select>
</mapper>
6.啓動類
package com.itheima;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* SpringBoot啓動類
* @author lenovo
*
*/
@SpringBootApplication
@MapperScan("com.itheima.mapper")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
實現的效果大致如下
6. 使用shiro攔截器實現授權頁面攔截
改動如下
@Configuration
public class ShiroConfig {
/**
* 創建ShiroFilterFactoryBean
*/
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
/**
* 常用的過濾器:annon 無需登錄,可以訪問
* authc:必須認證纔可以訪問
* user:如果使用remberme的功能 可以直接訪問
* perms:該資源必須授權
* role:該資源必須得到角色權限纔可以訪問
*/
HashMap<String, String> filterMap = new HashMap<>();
filterMap.put("/addOrder","authc");
filterMap.put("/updateOrder","authc");
filterMap.put("/tologin","anon");
filterMap.put("/deleteOrder","perms[user:add]"); //沒有權限直接401,光登錄成功還不行
filterMap.put("/","authc");
shiroFilterFactoryBean.setLoginUrl("/login");
shiroFilterFactoryBean.setUnauthorizedUrl("/noauth");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactoryBean;
}
/**
* 創建DefaultWebSecurityManager
*/
@Bean(name="securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm")UserRealm userRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(userRealm);
return securityManager;
}
/**
* 創建Realm
*/
@Bean(name="userRealm")
public UserRealm getRealm(){
return new UserRealm();
}
}
7.給用戶授予權限
public class UserRealm extends AuthorizingRealm {
@Autowired
private UserserServiceImpl UserserServiceImpl;
/**
* 執行授權邏輯
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
System.out.println("執行授權邏輯");
//給資源進行授權
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//添加資源的授權的字符串
info.addStringPermission("user:add"); // 這裏一定要和前面的config 一致
return info;
}
/**
* 執行認證邏輯
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
User user = UserserServiceImpl.findByName(token.getUsername());
if(user==null){
//用戶名不存在
return null;//shiro底層會拋出UnKnowAccountException
}
//2.判斷密碼
return new SimpleAuthenticationInfo("",user.getPassword(),"");
}
}
8.Mybaties和授權的結合
對所有的增 改 刪 增加了權限
@Configuration
public class ShiroConfig {
/**
* 創建ShiroFilterFactoryBean
*/
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
/**
* 常用的過濾器:annon 無需登錄,可以訪問
* authc:必須認證纔可以訪問
* user:如果使用remberme的功能 可以直接訪問
* perms:該資源必須授權
* role:該資源必須得到角色權限纔可以訪問
*/
HashMap<String, String> filterMap = new HashMap<>();
filterMap.put("/addOrder","authc");
filterMap.put("/updateOrder","authc");
filterMap.put("/deleteOrder","authc");
filterMap.put("/tologin","anon");
filterMap.put("/deleteOrder","perms[user:delete]"); //沒有權限直接401,光登錄成功還不行
filterMap.put("/updateOrder","perms[user:update]"); //沒有權限直接401,光登錄成功還不行
filterMap.put("/addOrder","perms[user:add]"); //沒有權限直接401,光登錄成功還不行
filterMap.put("/","authc");
shiroFilterFactoryBean.setLoginUrl("/login");
shiroFilterFactoryBean.setUnauthorizedUrl("/noauth");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactoryBean;
}
/**
* 創建DefaultWebSecurityManager
*/
@Bean(name="securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm")UserRealm userRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(userRealm);
return securityManager;
}
/**
* 創建Realm
*/
@Bean(name="userRealm")
public UserRealm getRealm(){
return new UserRealm();
}
}
結合數據庫添加權限的判斷
public class UserRealm extends AuthorizingRealm {
@Autowired
private UserserServiceImpl UserserServiceImpl;
/**
* 執行授權邏輯
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
System.out.println("執行授權邏輯");
//給資源進行授權
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//添加資源的授權的字符串
//獲取當前登錄的用戶
Subject subject = SecurityUtils.getSubject();
User user = (User) subject.getPrincipal(); -------> 注意這裏獲取的user其實也就
User byId = UserserServiceImpl.getById(user.getId());
info.addStringPermission(byId.getPerms());
return info;
}
/**
* 執行認證邏輯
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
User user = UserserServiceImpl.findByName(token.getUsername());
if(user==null){
//用戶名不存在
return null;//shiro底層會拋出UnKnowAccountException
}
//2.判斷密碼![在這裏插入圖片描述](https://img-blog.csdnimg.cn/20191229162939534.gif)
return new SimpleAuthenticationInfo(user,user.getPassword(),""); ----> user爲了subject.getPrincipal();獲取
}
}
9. Thymeleaf 整合shiro
1. 添加依賴
<!-- thymel對shiro的擴展座標 -->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
2. ShiroConfig 增加配置類
/**
* 配置ShiroDialect,用於thymeleaf和shiro標籤配合使用
*/
@Bean
public ShiroDialect getShiroDialect(){
return new ShiroDialect();
}
3.整改前臺,當含有某個權限的時候,顯示該功能欄
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html xmlns:shiro="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<h1>訂單系統</h1>
<br>
<div shiro:hasPermission="user:select">
<a href="showOrder">查詢訂單</a>
</div>
<br>
<div shiro:hasPermission="user:add">
<a href="addOrder">添加訂單</a>
<br>
</div>
<div shiro:hasPermission="user:delete">
<a href="deleteOrder">刪除訂單</a>
<br></div>
<div shiro:hasPermission="user:update">
<a href="updateOrder">修改訂單</a>
</div>
</form>
</body>
</html>
最後看下實際效果圖吧,(展示的時候有點小翻車…)