Shiro整合-Springboot+mybatis-plus

1.初始登陆代码

1.1.application.yml(配置文件)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
mapper-locations: classpath:mapper/* .xml
spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/shirodb?characterEncoding=utf-8&useSSL=false
username: root
password: 123456
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
shiro:
loginUrl: /myController/userLogin

1.2.pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
<?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.7.16-SNAPSHOT</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.gaomu</groupId>
<artifactId>spring_shiro</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring_shiro</name>
<description>spring_shiro</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-web-starter</artifactId>
<version>1.9.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.3.1</version>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.9.0</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
</pluginRepository>
</pluginRepositories>
</project>

1.3.ShingShiroApplication(启动主类)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.gaomu.spring_shiro;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan("com.gaomu.spring_shiro.mapper")
public class SpringShiroApplication {

public static void main(String[] args) {
​ SpringApplication.*run*(SpringShiroApplication.class, args);
​ }

}

1.4.UserService(服务层接口)

1
2
3
4
5
6
7
8
9
package com.gaomu.spring_shiro.service;

import com.gaomu.spring_shiro.entity.User;

public interface UserService {
//用户登陆方法
User getUserInfoByName(String name);
}

1.5.UserServoceImpl(服务层实现)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.gaomu.spring_shiro.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.gaomu.spring_shiro.entity.User;
import com.gaomu.spring_shiro.mapper.UserMapper;
import com.gaomu.spring_shiro.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public User getUserInfoByName(String name) {
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("name", name);
User user = userMapper.selectOne(wrapper);
return user;
}
}

1.6.UserMapper(数据层接口)

1
2
3
4
5
6
7
8
package com.gaomu.spring_shiro.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.gaomu.spring_shiro.entity.User;
import org.springframework.stereotype.Repository;

@Repository
public interface UserMapper extends BaseMapper<User> {
}

1.7.User(定义数据模型)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.gaomu.spring_shiro.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Integer id;
private String name;
private String pwd;
private Integer rid;
}

1.8.ShiroConfig(shiro配置类)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package com.gaomu.spring_shiro.config;

import com.gaomu.spring_shiro.realm.MyRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ShiroConfig {
@Autowired
private MyRealm myRealm;
//配置securityManager
@Bean
public DefaultWebSecurityManager defaultWebSecurityManager(){
//1创建defaultWebSecurityManger对象
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
//2创建加密对象,设置相关属性
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
//2.1采用md5加密
matcher.setHashAlgorithmName("md5");
//2.2采用三次迭代
matcher.setHashIterations(3);
//3将加密对象存储到myRealm中
myRealm.setCredentialsMatcher(matcher);
//4将myRealm存入到defaultWebSecurityManger对象
defaultWebSecurityManager.setRealm(myRealm);
//5返回
return defaultWebSecurityManager;
}
//配置shiro内置过滤器拦截范围
@Bean
public DefaultShiroFilterChainDefinition shiroFilterChainDefinition(){
DefaultShiroFilterChainDefinition definition = new DefaultShiroFilterChainDefinition();
//设置不认真可以访问的资源
definition.addPathDefinition("/myController/userLogin","anon");
definition.addPathDefinition("/myController/login", "anon");
//设置需要进行登陆认证的拦截范围
definition.addPathDefinition("/**", "authc");
return definition;
}

}

1.9.MyRealm(定义Realm)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package com.gaomu.spring_shiro.realm;

import com.gaomu.spring_shiro.entity.User;
import com.gaomu.spring_shiro.service.UserService;
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.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MyRealm extends AuthorizingRealm {
@Autowired
private UserService userService;

//自定义授权方法
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}

//自定义获取登陆认证信息
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//1获取用户身份信息
String name = authenticationToken.getPrincipal().toString();
//2调用业务层获取用户信息(数据库)
User user = userService.getUserInfoByName(name);
//3非空判断,完成封装
if(user != null){
AuthenticationInfo info = new SimpleAuthenticationInfo(
authenticationToken.getPrincipal(),
user.getPwd(),
ByteSource.Util.bytes("salt"),
authenticationToken.getPrincipal().toString()
);
return info;
}
return null;
}
}

1.11.MyController(控制层)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package com.gaomu.spring_shiro.controller;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;


@Controller
@RequestMapping("myController")
public class MyController {
@GetMapping("userLogin")
@ResponseBody
public String userLogin(String name, String pwd){
//1获取subject对象
Subject subject = SecurityUtils.getSubject();
//2封装请求数据到token
AuthenticationToken token = new UsernamePasswordToken(name, pwd);
//3调用login方法进行登陆认证
try {
subject.login(token);
return "登陆成功";
} catch (AuthenticationException e) {
e.printStackTrace();
System.out.println("登陆失败");
return "登陆失败";
}
}
}

1.12.数据库用户表

image-20230910225255835

get请求 登陆测试

image-20230910193730075

image-20230910193810557

2.前端实现shiro整合Thymeleaf

2.1.pom.xml(导入Thymeleaf依赖)

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

2.2.application.yml (更改重定向页面)

1
2
shiro:
loginUrl: /myController/login

2.2.login.html(登陆页面)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>Shiro登录认证</h1>
<form action="/myController/userLogin">
<div>用户名:<input type="text" name="name" value=""></div>
<div>密码 :<input type="password" name="pwd" value=""></div>
<div><input type="submit" value="登录"></div>
</form>

</body>
</html>

2.3.index.html(登陆成功页面)

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>shiro登录认证后主页面</h1>
<br>
登录用户为:<span th:text="${session.user}"></span>
</body>
</html>

2.4.Mycontroller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpSession;


@Controller
@RequestMapping("myController")
public class MyController {
@GetMapping("login")
public String login(){
return "login";
}

@GetMapping("userLogin")
public String userLogin(String name, String pwd, HttpSession session){
//1获取subject对象
Subject subject = SecurityUtils.getSubject();
//2封装请求数据到token
AuthenticationToken token = new UsernamePasswordToken(name, pwd);
//3调用login方法进行登陆认证
try {
subject.login(token);
//return "登陆成功";
session.setAttribute("user", token.getPrincipal().toString());
return "index";
} catch (AuthenticationException e) {
e.printStackTrace();
System.out.println("登陆失败");
return "登陆失败";
}
}
}

3.多realm实现

3.1.多个realm实现原理

​ 当应用程序配置多个Realm时,例如:用户名密码校验、手机号验证码校验等等。Shiro的ModularRealmAuthenticator会使用内部的AuthenticationStrategy.组件判断认证是成功还是失败。

​ AuthenticationStrategy是一个无状态的组件,它在身份验证尝试中被询问4次(这4次交互所需的任何必要的状态将被作为方法参数):
(1)在所有Realm被调用之前

(2)在调用Realm的 getAuthenticationInfo方法之前

(3)在调用Realm的 getAuthenticationInfo·方法之后

(4)在所有Realm被调用之后

image-20230910205042594

4.remember me

4.1.简介

​ Shiro·提供了记住我(RememberMe)的功能,比如访问一些网站时,关闭了浏览器,下次再打开时还是能记住你是谁,下次访问时无需再登录即可访问。

4.2.基本流程

1、基本流程
(1)首先在登录页面选中RememberMe然后登录成功;如果是浏览器登录,一般会把RememberMe_的Cookie写到客户端并保存下来;

(2)关闭浏览器再重新打开;会发现浏览器还是记住你的;

(3)访问一般的网页服务器端,仍然知道你是谁,且能正常访问;

(4)但是,如果我们访问电商平台时,如果要查看我的订单或进行支付时,此时还
是需要再进行身份认证的,以确保当前用户还是你。

4.3.ShiroConfig (添加RememberMe和用户拦截)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
package com.gaomu.spring_shiro.config;

import com.gaomu.spring_shiro.realm.MyRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.Cookie;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ShiroConfig {
@Autowired
private MyRealm myRealm;
//配置securityManager
@Bean
public DefaultWebSecurityManager defaultWebSecurityManager(){
//1创建defaultWebSecurityManger对象
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
//2创建加密对象,设置相关属性
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
//2.1采用md5加密
matcher.setHashAlgorithmName("md5");
//2.2采用三次迭代
matcher.setHashIterations(3);
//3将加密对象存储到myRealm中
myRealm.setCredentialsMatcher(matcher);
//4将myRealm存入到defaultWebSecurityManger对象
defaultWebSecurityManager.setRealm(myRealm);
//4.5设置rememberMe
defaultWebSecurityManager.setRememberMeManager(rememberMeManager());
//5返回
return defaultWebSecurityManager;
}
//cookie配置
public SimpleCookie rememberMeCookie(){
SimpleCookie cookie = new SimpleCookie("rememberMe");
//设置跨域
//cookie.setDomain(domain)
cookie.setPath("/");
cookie.setHttpOnly(true);
cookie.setMaxAge(30*24*60*60);
return cookie;
}
//创建Shiro的cookie管理对象
public CookieRememberMeManager rememberMeManager(){
CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
cookieRememberMeManager.setCookie(rememberMeCookie());
cookieRememberMeManager.setCipherKey("1234567891234567".getBytes());
return cookieRememberMeManager;
}

//配置shiro内置过滤器拦截范围
@Bean
public DefaultShiroFilterChainDefinition shiroFilterChainDefinition(){
DefaultShiroFilterChainDefinition definition = new DefaultShiroFilterChainDefinition();
//设置不认真可以访问的资源
definition.addPathDefinition("/myController/userLogin","anon");
definition.addPathDefinition("/myController/login", "anon");
//设置需要进行登陆认证的拦截范围
definition.addPathDefinition("/**", "authc");
//添加用户过滤器(rememberMe)
definition.addPathDefinition("/**", "user");
return definition;
}

}

4.4.MyController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@GetMapping("userLogin")
public String userLogin(String name, String pwd,
@RequestParam(defaultValue = "false") boolean rememberMe,
HttpSession session){
//1获取subject对象
Subject subject = SecurityUtils.getSubject();
//2封装请求数据到token
AuthenticationToken token = new UsernamePasswordToken(name, pwd, rememberMe);
//3调用login方法进行登陆认证
try {
subject.login(token);
//return "登陆成功";
session.setAttribute("user", token.getPrincipal().toString());
return "index";
} catch (AuthenticationException e) {
e.printStackTrace();
System.out.println("登陆失败");
return "登陆失败";
}
}

@GetMapping("userLoginRm")
public String userLogin(HttpSession session){
session.setAttribute("user", "rememberMe");
return "index";
}

4.5.login.html(添加记住登陆勾选框)

1
2
3
4
5
6
<form action="/myController/userLogin">
<div>用户名:<input type="text" name="name" value=""></div>
<div>密码 :<input type="password" name="pwd" value=""></div>
<div>记住用户:<input type="checkbox" name="rememberMe" value="true"></div>
<div><input type="submit" value="登录"></div>
</form>

5.用户登出

5.1.index.html

1
2
3
4
5
6
7
<body>
<h1>shiro登录认证后主页面</h1>
<br>
登录用户为:<span th:text="${session.user}"></span>
<br>
<a href="/logout">登出</a>
</body>

5.2.ShiroConfig

1
2
//设置需要进行登出过滤器
definition.addPathDefinition("/logout", "logout");

6.授权

​ 用户登录后,需要验证是否具有指定角色指定权限。Shiro也提供了方便的工具进行判断。

​ 这个工具就是Realm的doGetAuthorizationInfo方法进行判断。触发权限判断的有两种方式

(1)在页面中通过shiro :***属性判断

(2)在接口服务中通过注解@Requires***进行判断

6.1.后端接口服务注解

​ 通过给接口服务方法添加注解可以实现权限校验,可以加在控制器方法上,也可以加在业务方法上,一般加在控制器方法上。常用注解如下:
(1) @RequiresAuthenticationk
​ 验证用户是否登录,等同于方法subject.isAuthenticated()

(2)@RequiresUserl’
验证用户是否被记忆:
登录认证成功subject.i.sAuthenticated()为true

​ 登录后被记忆subject.i.sRemembered()为true

(3)@RequiresGuest

​ 验证是否是一个guest的请求,是否是游客的请求-此时subject.getPrincipal.()为nulle

(4)@RequiresRolese

​ 验证subject是否有相应角色,有角色访问方法,没有则会抛出异常AuthorizationException。

​ 例如:@RequiresRoles(“aRoleName”)

​ void someMethod();

​ 只有subject有aRoleName角色才能访问方法someMethod()

(5) @RequiresPermissionse
验证subject是否有相应权限,有权限访问方法,没有则会抛出异常AuthorizationException。

​ 例如:@RequiresPermissions· ( “file:read”, “wite: aFile.txt”)

​ void- someMethod() ;

​ subject必须同时含有file:read和wite:aFile.txt权限才能访问方法someMethod()

6.2.数据库角色表

image-20230910225337448

image-20230910225351209

6.3.UserMapper(配置查询数据库角色接口)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.gaomu.spring_shiro.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.gaomu.spring_shiro.entity.User;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;
import java.util.List;

@Repository
public interface UserMapper extends BaseMapper<User> {

@Select("SELECT name FROM role WHERE id IN (\n" +
"\tSELECT rid FROM role_user WHERE uid = (\n" +
"\t\tSELECT id FROM USER WHERE NAME=#{principal}\n" +
"\t)\n" +
")")
List<String> getUserRoleInfoMapper(@Param("principal") String principal);
}

6.4.UserService(配置查询角色服务层接口)

1
2
//根据用户名查询角色信息
List<String> getUserRoleInfo(String principal);

6.5.UserServiceImpl(实现查询接口)

1
2
3
4
5
//根据用户查询角色信息
@Override
public List<String> getUserRoleInfo(String principal) {
return userMapper.getUserRoleInfoMapper(principal);
}

6.6.MyController(添加验证角色授权接口)

1
2
3
4
5
6
7
8
//登陆认证验证角色
@RequiresRoles("admin")
@GetMapping("userLoginRoles")
@ResponseBody
public String userLoginRoles(){
System.out.println("登陆认证验证角色");
return "验证角色成功";
}

6.7.index.html(添加授权测试超链接)

1
2
<br>
<a href="/myController/userLoginRoles">测试授权</a>

6.8.MyRealm(配置doGet授权方法)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//自定义授权方法:获取当前登陆用的角色、权限信息、返回给shiro用来进行授权认证
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("自定义授权方法");
//1获取用户身份信息
String principal = principalCollection.getPrimaryPrincipal().toString();
//2调用业务层获取角色信息(数据库)
List<String> roles = userService.getUserRoleInfo(principal);
System.out.println("当前用户角色信息:" + roles);
//3创建对象,封装当前登陆用户的、权限信息
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addRoles(roles);
//info.addRole("admin");
//4返回信息
return info;
}

7.权限验证

7.1.建立权限表和关联表

image-20230910233802810

image-20230910233823019

7.2.UserMapper(通过角色信息查询权限信息)

1
2
3
4
5
6
7
8
9
10
11
12
@Select({
"<script>",
"select info FROM permissions WHERE id IN ",
"(SELECT pid FROM role_ps WHERE rid IN (",
"SELECT id FROM role WHERE NAME IN ",
"<foreach collection='roles' item='name' open='(' separator=' , ' close=')'>",
"#{name}",
"</foreach>",
"))",
"</script>"
})
List<String> getUserPermissionInfoMapper(@Param("roles")List<String> roles);

7.3.UserService

1
2
//获取用户角色的权限信息
List<String> getUserPermissionInfo(List<String> roles);

7.4.UserServiceImpl

1
2
3
4
5
//根据角色查询权限信息
@Override
public List<String> getUserPermissionInfo(List<String> roles) {
return userMapper.getUserPermissionInfoMapper(roles);
}

7.5.MyRealm(添加权限信息)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("自定义授权方法");
//1获取用户身份信息
String principal = principalCollection.getPrimaryPrincipal().toString();
//2调用业务层获取角色信息(数据库)
List<String> roles = userService.getUserRoleInfo(principal);
System.out.println("当前用户角色信息:" + roles);
//2.5调用业务层获取用户权限信息(数据库)
List<String> permissions = userService.getUserPermissionInfo(roles);
System.out.println("当前用户的权限信息:" + permissions);
//3创建对象,封装当前登陆用户的、权限信息
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addRoles(roles);
info.addStringPermissions(permissions);
//info.addRole("admin");
//4返回信息
return info;
}

7.6.MyController

1
2
3
4
5
6
7
8
//登陆认证验证权限
@RequiresPermissions("user:delete")
@GetMapping("userPermissions")
@ResponseBody
public String userLoginPermissions(){
System.out.println("登陆认证验证权限");
return "验证权限成功";
}

7.7.index.html

1
2
<br>
<a href="/myController/userPermissions">测试权限</a>

8.异常处理

8.1.PermissionsException(异常处理)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.gaomu.spring_shiro.controller;

import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

@ControllerAdvice
public class PermissionsException {
@ResponseBody
@ExceptionHandler(UnauthorizedException.class)
public String unauthorizedException(Exception e){
return "无权限";
}
@ResponseBody
@ExceptionHandler(AuthorizationException.class)
public String authorizationException(Exception e){
return "权限认证失败";
}
}

9.前端页面显示权限处理

9.1.Thymeleaf中常用的shiro属性

  • guest 标签

shiro:guest


用户没有身份验证时显示相应信息,即游客访问信息。


用户已经身份验证/记住我登录后显示相应的信息。

  • authenticated 标签

shiro:authenticated


用户已经身份验证通过,即Subject.login.登录成功,不是记住我登录的。

  • notAuthenticated 标签

shiro:notAuthenticated


用户已经身份验证通过,即没有调用Subject.login进行登录,包括记住我自动登录的也属于未进行身份验证。

  • principal 标签

<shiro: principal/>
<shiro: principal property=”username”/>

相当于((User)Subject.getPrincipals()).getUsername()。

lacksPermission标签
<shiro:lacksPermission name=”org:create” >


如果当前Subject没有权限将显示body体内容。

  • hasRole标签
    <shiro:hasRol.e name=”admin”>


如果当前Subject有角色将显示body体内容。

  • hasAnyRoles 标签
    <shiro:hasAnyRoles name=”admin, user”>


如果当前Subject有任意一个角色(或的关系)将显示body体内容。

  • *** lacksRole标签***
    <shiro: lacksRole: name=”abc”>

</shiro: lacksRole>

如果当前Subject没有角色将显示body 体内容。

  • hasPermission.标签
    <shiro:hasPermission name=”user:create”>


如果当前Subject有权限将显示body 体内容-

9.2.pom.xml

1
2
3
4
5
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>

9.3.ShiroConfig

1
2
3
4
@Bean
public ShiroDialect shiroDialect(){
return new ShiroDialect();
}

9.4.index.html

1
2
3
4
5
6
7
<html lang="en" xmlns:shiro="http://www.w3.org/1999/xhtml">
------------

<br>
<a shiro:hasRole="admin" href="/myController/userLoginRoles">测试授权</a>
<br>
<a shiro:hasPermission="user:delete" href="/myController/userPermissions">测试权限</a>