一、Shiro框架簡介
1.1、shiro介紹
Apache Shiro是一個強大且易用的Java安全框架,執行身份驗證、授權、密碼學和會話管理。使用Shiro的易於理解的API,您可以快速、輕鬆地獲得任何應用程序,從最小的移動應用程序到最大的網絡和企業應用程序。
Apache Shiro 體系結構
- Authentication 認證 ---- 用戶登錄
- Authorization 授權 — 用戶具有哪些權限
- Cryptography 安全數據加密
- Session Management 會話管理
- Web Integration web系統集成
- Interations 集成其它應用,spring、緩存框架
- subject:上面標記爲1的是shiro的主體部分subject,可以理解爲當前的操作用戶
- Security Manager:Security Manager爲Shiro的核心,shiro是通過security Manager來提供安全服務的,security Manager管理着Session Manager、Cache Manager等其他組件的實例:
- Authenticator認證器,管理我們的登錄登出);
- Authorizer授權器,負責賦予主體subject有哪些權限;
- Session Manager是shiro自己實現的一套session管理機制,可以不借助任何web容器的情況下使用session;
- Session Dao提供了session的增刪改查操作;
- cache Manager緩存管理器,用於緩存角色數據和權限數據;
- Pluggable Realms是shiro與數據庫/數據源之間的橋樑,shiro獲取認證信息、權限數據、角色數據都是通過Realms來獲取;
-
cryptography:用來做加密的,使用它可以非常方便快捷的進行數據加密。
-
上圖組件之間的工作流程:主體提交請求到Security Manager,然後由Security Manager調用Authenticator去做認證,而Authenticator去獲取認證數據的時候是通過Realms從數據源中來獲取的,然後把從數據源中拿到的認證信息與主體提交過來的認證信息做比對。授權器Authorizer也是一樣。
Shiro的核心API:
- Subject: 用戶主體(把操作交給SecurityManager)
- SecurityManager:安全管理器(關聯Realm)
- Realm:Shiro連接數據庫的橋樑
1.2、shiro認證
Shiro的認證流程
-
創建Security Manager:Security Manager是用來提供安全服務的,所以在做shiro認證的時候要先創建此對象
-
主體Subject提交請求給Security Manager
-
Security Manager調用Authenticator組件做認證
-
Authenticator通過Realm來從數據源中獲取認證數據
以下通過代碼來演示shiro是如何做認證的
引入依賴
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>RELEASE</version>
</dependency>
使用示例
package com.maltose.shiro.test;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.SimpleAccountRealm;
import org.apache.shiro.subject.Subject;
import org.junit.Before;
import org.junit.Test;
/**
* @auther sgw
* @create 2019-12-31 14:06
* @todo 創建一個測試類,測試認證
*/
public class AuthenticationTest {
//除了SimpleAccountRealm還有JdbcRealm等可以使用
SimpleAccountRealm simpleAccountRealm = new SimpleAccountRealm();
//在認證之前先在Realm中添加一個用戶,來模擬頁面傳來的用戶信息;創建Security Manager的時候要用到Realm
@Before
public void addUser() {
simpleAccountRealm.addAccount("maltose","123456");
}
@Test
public void testAutentication() {
//1.構建Security Manager環境(Security Manager是用來提供安全服務的,所以在做shiro認證的時候要先創建此對象,創建Security Manager對象之後要設置Realm,Realm是前端頁面用戶提交過來的信息)
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
defaultSecurityManager.setRealm(simpleAccountRealm);
//2.獲取向Security Manager提交請求的subject,而主體subject可以通過shiro提供的一個工具類SecurityUtils來獲取
//使用SecurityUtils之前要設置Security Manager環境
SecurityUtils.setSecurityManager(defaultSecurityManager);
Subject subject = SecurityUtils.getSubject();
//3.主體Subject提交請求給Security Manager --> subject.login(token);
//提交請求時需要一個token,所以要先創建token
UsernamePasswordToken token = new UsernamePasswordToken("xiehuaxin","123456");
subject.login(token);
//4. shiro提供了一個檢查主體subject是否認證的方法isAuthenticated(),此方法的返回結果是一個boolean值
System.out.println(subject.isAuthenticated());
subject.logout();
System.out.println(subject.isAuthenticated());
}
}
1.3、Shiro的授權
shiro授權流程
shiro授權流程與認證流程基本一致
-
創建Security Manager
-
主體subject授權
-
主體授權提交給Security Manager授權
-
Security Manager調用授權器Authorizer授權
-
通過Realm在數據庫或者緩存中來獲取授權的數據(角色數據和權限數據)
以下通過代碼來演示shiro是如何做授權的
package com.maltose.shiro.test;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.SimpleAccountRealm;
import org.apache.shiro.subject.Subject;
import org.junit.Before;
import org.junit.Test;
/**
* @auther sgw
* @create 2019-12-31 14:15
* @todo 創建一個測試類,測試授權
*/
public class AuthenticationTest {
SimpleAccountRealm simpleAccountRealm = new SimpleAccountRealm();
@Before
public void addUser() {
//添加用戶的時候爲此用戶添加角色,一個用戶可以擁有一個或多個角色
simpleAccountRealm.addAccount("maltose", "123456", "admin", "user");
}
@Test
public void testAutentication() {
//1.構建Security Manager環境(Security Manager是用來提供安全服務的,所以在做shiro認證的時候要先創建此對象,創建Security Manager對象之後要設置Realm)
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
defaultSecurityManager.setRealm(simpleAccountRealm);
//2.獲取向Security Manager提交請求的subject,而主體subject可以通過shiro提供的一個工具類SecurityUtils來獲取
SecurityUtils.setSecurityManager(defaultSecurityManager);//使用SecurityUtils之前要設置Security Manager環境
Subject subject = SecurityUtils.getSubject();
//3.主體Subject提交請求給Security Manager --> subject.login(token);
UsernamePasswordToken token = new UsernamePasswordToken("xiehuaxin", "123456");//提交請求時需要一個token,所以要先創建token
subject.login(token);
//4. shiro提供了一個檢查主體subject是否認證的方法isAuthenticated(),此方法的返回結果是一個boolean值
System.out.println(subject.isAuthenticated());
//校驗角色
subject.checkRoles("admin");
}
}
1.3、shiro加密
加密加鹽工具類
public class ShiroUtil {
/**
* 生成32的隨機鹽值
*/
public static String createSalt(){
return UUID.randomUUID().toString().replaceAll("-", "");
}
/**
* 加鹽加密
* @param srcPwd 原始密碼
* @param saltValue 鹽值
*/
public static String salt(Object srcPwd, String saltValue){
return new SimpleHash("MD5", srcPwd, saltValue, 1024).toString();
}
}
在創建用戶時,生成隨機鹽值,然後將加密後的密碼與對應的鹽值存入數據庫。如:
public class User {
/**
* ID
*/
private String id;
/**
* 登錄用戶
*/
@NotEmpty(message = "用戶名:用戶名不能爲空")
private String username;
/**
* 登錄密碼
*/
@Length(min = 6, message = "密碼:密碼長度不能低於6位")
@NotEmpty(message = "密碼:密碼不能爲空")
private String password;
/**
* 鹽值
*/
private String saltValue;
/**
* 手機號
*/
private String mobile;
/**
* 暱稱
*/
private String nickname;
/**
* 是否凍結
*/
private Integer isFrozen;
/**
* 創建時間
*/
private Date createTime;
public User() {
}
public User(String id, String username, String password, String saltValue, String mobile, String nickname,
Integer isFrozen, Date createTime) {
this.id = id;
this.username = username;
this.password = password;
this.saltValue = saltValue;
this.mobile = mobile;
this.nickname = nickname;
this.isFrozen = isFrozen;
this.createTime = createTime;
}
/**
* 創建新的用戶
* @param username 用戶名
* @param password 密碼
* @param nickname 暱稱
* @param mobile 手機號
*/
public static User createUser(String username, String password, String nickname, String mobile){
String saleValue = ShiroUtil.createSalt();
return new User(ShiroUtil.createSalt(), username, ShiroUtil.salt(password, ByteSource.Util.bytes(saleValue).toString()),
saleValue, mobile, nickname, 0, new Date());
}
//省略set/get方法
}
shiro進行認證
用戶加密完成後,在Shiro中認證時,加鹽加密用戶輸入的密碼,然後和庫中的對比是否一致即可:
public class MyRealm extends AuthorizingRealm {
@Autowired
private UserMapper userMapper;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
//todo:獲取用戶的權限
return authorizationInfo;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
User user = this.userMapper.selectByPrimaryKey(token.getUsername());
if (user == null){
throw new AuthenticationException("用戶不存在!");
}
//鹽值
ByteSource salt = ByteSource.Util.bytes(user.getSaltValue());
String saltPassword = ShiroUtil.salt(token.getPassword(), salt.toString());
if (!user.getPassword().equals(saltPassword)){
throw new AuthenticationException("輸入密碼不正確!");
}
if (user.getIsFrozen() == 0){
throw new AuthenticationException("用戶已凍結!");
}
//第4個參數是realm名稱
return new SimpleAuthenticationInfo(token.getPrincipal(), token.getPassword(), salt, getName());
}
}
二、Spring Boot整合Shiro實現用戶認證
添加整合依賴
<!-- shiro與spring整合依賴 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
自定義Realm類
package com.maltose.shiro;
import org.apache.shiro.subject.PrincipalCollection;
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;
/**
* 自定義Realm
* @author sgw
*
*/
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;
}
}
編寫Shiro配置類(*)
package com.maltose.shiro;
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;
/**
* Shiro的配置類
* @author sgw
*
*/
@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();
//關聯realm
securityManager.setRealm(userRealm);
return securityManager;
}
/**
* 創建Realm
*/
@Bean(name="userRealm")
public UserRealm getRealm(){
return new UserRealm();
}
}
使用Shiro內置過濾器實現頁面攔截
package com.maltose.shiro;
import java.util.LinkedHashMap;
import java.util.Map;
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;
/**
* Shiro的配置類
* @author sgw
*
*/
@Configuration
public class ShiroConfig {
/**
* 創建ShiroFilterFactoryBean
*/
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//設置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
//添加Shiro內置過濾器
/**
* Shiro內置過濾器,可以實現權限相關的攔截器
* 常用的過濾器:
* anon: 無需認證(登錄)可以訪問
* authc: 必須認證纔可以訪問
* user: 如果使用rememberMe的功能可以直接訪問
* perms: 該資源必須得到資源權限纔可以訪問
* role: 該資源必須得到角色權限纔可以訪問
*/
Map<String,String> filterMap = new LinkedHashMap<String,String>();
/*filterMap.put("/add", "authc");
filterMap.put("/update", "authc");*/
filterMap.put("/testThymeleaf", "anon");
filterMap.put("/*", "authc");
//修改調整的登錄頁面
shiroFilterFactoryBean.setLoginUrl("/toLogin");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactoryBean;
}
/**
* 創建DefaultWebSecurityManager
*/
@Bean(name="securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm")UserRealm userRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//關聯realm
securityManager.setRealm(userRealm);
return securityManager;
}
/**
* 創建Realm
*/
@Bean(name="userRealm")
public UserRealm getRealm(){
return new UserRealm();
}
}
實現用戶認證(登錄)操作
設計登錄頁面
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>登錄頁面</title>
</head>
<body>
<h3>登錄</h3>
<form method="post" action="login">
用戶名:<input type="text" name="name"/><br/>
密碼:<input type="password" name="password"/><br/>
<input type="submit" value="登錄"/>
</form>
</body>
</html>
編寫Controller的登錄邏輯
/**
* 登錄邏輯處理
*/
@RequestMapping("/login")
public String login(String name,String password,Model model){
/**
* 使用Shiro編寫認證操作
*/
//1.獲取Subject
Subject subject = SecurityUtils.getSubject();
//2.封裝用戶數據
UsernamePasswordToken token = new UsernamePasswordToken(name,password);
//3.執行登錄方法
try {
subject.login(token);
//登錄成功
//跳轉到test.html
return "redirect:/testThymeleaf";
} catch (UnknownAccountException e) {
//e.printStackTrace();
//登錄失敗:用戶名不存在
model.addAttribute("msg", "用戶名不存在");
return "login";
}catch (IncorrectCredentialsException e) {
//e.printStackTrace();
//登錄失敗:密碼錯誤
model.addAttribute("msg", "密碼錯誤");
return "login";
}
}
編寫Realm的判斷邏輯
package com.maltose.shiro;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
/**
* 自定義Realm
* @author sgw
*
*/
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("執行認證邏輯");
//假設數據庫的用戶名和密碼
String name = "eric";
String password = "123456";
//編寫shiro判斷邏輯,判斷用戶名和密碼
//1.判斷用戶名
UsernamePasswordToken token = (UsernamePasswordToken)arg0;
if(!token.getUsername().equals(name)){
//用戶名不存在
return null;//shiro底層會拋出UnKnowAccountException
}
//2.判斷密碼
return new SimpleAuthenticationInfo("",password,"");
}
}
整合MyBatis實現登錄
導入mybatis相關的依賴
<!-- 導入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>
配置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
編寫User實體
package com.maltose.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;
}
}
編寫UserMapper接口
package com.maltose.mapper;
import com.maltose.domain.User;
public interface UserMapper {
public User findByName(String name);
}
編寫UserMapper.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.maltose.mapper.UserMapper">
<select id="findByName" parameterType="string" resultType="user">
SELECT id,
NAME,
PASSWORD
FROM
user where name = #{value}
</select>
</mapper>
編寫業務(service)接口和實現
package com.maltose.service;
import com.maltose.domain.User;
public interface UserService {
public User findByName(String name);
}
實現
package com.maltose.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.maltose.domain.User;
import com.maltose.mapper.UserMapper;
import com.maltose.service.UserService;
@Service
public class UserServiceImpl implements UserService{
//注入Mapper接口
@Autowired
private UserMapper userMapper;
@Override
public User findByName(String name) {
return userMapper.findByName(name);
}
}
啓動類添加@MapperScan註解
package com.maltose;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* SpringBoot啓動類
* @author sgw
*
*/
@SpringBootApplication
@MapperScan("com.maltose.mapper")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
修改UserRealm
package com.maltose.shiro;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import com.maltose.domain.User;
import com.maltose.service.UserService;
/**
* 自定義Realm
* @author lenovo
*
*/
public class UserRealm extends AuthorizingRealm{
/**
* 執行授權邏輯
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
System.out.println("執行授權邏輯");
return null;
}
@Autowired
private UserService userSerivce;
/**
* 執行認證邏輯
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {
System.out.println("執行認證邏輯");
//編寫shiro判斷邏輯,判斷用戶名和密碼
//1.判斷用戶名
UsernamePasswordToken token = (UsernamePasswordToken)arg0;
User user = userSerivce.findByName(token.getUsername());
if(user==null){
//用戶名不存在
return null;//shiro底層會拋出UnKnowAccountException
}
//2.判斷密碼
return new SimpleAuthenticationInfo("",user.getPassword(),"");
}
}
三、Spring Boot整合Shiro實現用戶授權
3.1. 使用Shiro內置過濾器攔截資源
/**
* 創建ShiroFilterFactoryBean
*/
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//設置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
//添加Shiro內置過濾器
/**
* Shiro內置過濾器,可以實現權限相關的攔截器
* 常用的過濾器:
* anon: 無需認證(登錄)可以訪問
* authc: 必須認證纔可以訪問
* user: 如果使用rememberMe的功能可以直接訪問
* perms: 該資源必須得到資源權限纔可以訪問
* role: 該資源必須得到角色權限纔可以訪問
*/
Map<String,String> filterMap = new LinkedHashMap<String,String>();
/*filterMap.put("/add", "authc");
filterMap.put("/update", "authc");*/
filterMap.put("/testThymeleaf", "anon");
//放行login.html頁面
filterMap.put("/login", "anon");
//授權過濾器
//注意:當前授權攔截後,shiro會自動跳轉到未授權頁面
filterMap.put("/add", "perms[user:add]");
filterMap.put("/*", "authc");
//修改調整的登錄頁面
shiroFilterFactoryBean.setLoginUrl("/toLogin");
//設置未授權提示頁面
shiroFilterFactoryBean.setUnauthorizedUrl("/noAuth");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactoryBean;
}
3.2. 完成Shiro的資源授權
UserRealm:
/**
* 執行授權邏輯
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
System.out.println("執行授權邏輯");
//給資源進行授權
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//添加資源的授權字符串
info.addStringPermission("user:add");
return info;
}
四、thymeleaf和shiro標籤整合使用
4.1. 導入thymeleaf擴展座標
<!-- thymel對shiro的擴展座標 -->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
4.2. 配置ShiroDialect
在ShiroConfig類裏面添加getShiroDialect方法
/**
* 配置ShiroDialect,用於thymeleaf和shiro標籤配合使用
*/
@Bean
public ShiroDialect getShiroDialect(){
return new ShiroDialect();
}
4.3. 在頁面上使用shiro標籤
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>測試Thymeleaf的使用</title>
</head>
<body>
<h3 th:text="${name}"></h3>
<hr/>
<div shiro:hasPermission="user:add">
進入用戶添加功能: <a href="add">用戶添加</a><br/>
</div>
<div shiro:hasPermission="user:update">
進入用戶更新功能: <a href="update">用戶更新</a>
<br/>
</div>
<a href="toLogin">登錄</a>
</body>
</html>