【SpringBoot】SpringBoot基础教程(15)
前言:
本文内容:Shiro整合Mybatis、Shiro请求授权实现、Shiro整合Thymeleaf
推荐免费SpringBoot基础教程视频:【狂神说Java】SpringBoot最新教程通俗易懂_哔哩哔哩_bilibili
Shiro整合Mybatis
-
在pom文件中引入需要的依赖
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<!-- mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- log4j-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!-- druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.8</version>
</dependency>
<!-- mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<!-- lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency> -
新建
application.yaml
并进行配置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
29spring:
datasource:
username: root
password: 123456
url: jdbc:mysql://localhost:3306/mybatis?useSSL=true&serverTimezone=UTC
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
#SpringBoot默认是不注入这些的,需要自己绑定
#druid数据源专有配置
initialSize: 5
minIdle: 5
maxActive: 20
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
#配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入
#如果允许报错,java.lang.ClassNotFoundException: org.apache.Log4j.Properity
#则导入log4j 依赖就行
filters: stat,wall,log4j
maxPoolPreparedStatementPerConnectionSize: 20
useGlobalDataSourceStat: true
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500 -
在
resources
下新建mapper
文件夹 -
在
application.properties
1
2
3# 配置别名和mapper路径
mybatis.type-aliases-package=com.jokerdig.pojo
mybatis.mapper-locations=classpath:mapper/*.xml -
在包
pojo
下新建User.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18package com.jokerdig.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author Joker大雄
* @data 2022/7/27 - 11:23
**/
public class User {
private int id;
private String name;
private String pwd;
} -
在
mapper
包下新建UserMapper.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18package com.jokerdig.mapper;
import com.jokerdig.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
/**
* @author Joker大雄
* @data 2022/7/27 - 11:26
**/
public interface UserMapper {
// 登录
public User queryUserByName(String name);
} -
在
resources/mapper
下新建UserMapper.xml
1
2
3
4
5
6
7
8
9
10
11
12
<mapper namespace="com.jokerdig.mapper.UserMapper">
<!-- 登录-->
<select id="queryUserByName" parameterType="String" resultType="User">
select * from user where name=#{name}
</select>
</mapper> -
在
service
包下新建UserService.java
和UserServiceImpl.java
UserService
1
2
3
4
5
6
7
8
9
10
11
12package com.jokerdig.service;
import com.jokerdig.pojo.User;
/**
* @author Joker大雄
* @data 2022/7/27 - 11:31
**/
public interface UserService {
// 登录
public User queryUserByName(String name);
}UserServiceImpl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21package com.jokerdig.service;
import com.jokerdig.mapper.UserMapper;
import com.jokerdig.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @author Joker大雄
* @data 2022/7/27 - 11:32
**/
public class UserServiceImpl implements UserService{
private UserMapper mapper;
public User queryUserByName(String name) {
return mapper.queryUserByName(name);
}
} -
修改
UserRealm
,使其连接数据库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
44package com.jokerdig.config;
import com.jokerdig.pojo.User;
import com.jokerdig.service.UserService;
import org.apache.shiro.authc.*;
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;
/**
* @author Joker大雄
* @data 2022/7/26 - 11:12
**/
// 自定以 Realm extends AuthorizingRealm
public class UserRealm extends AuthorizingRealm {
private UserService userService;
// 授权
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("执行了授权");
return null;
}
// 认证
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("执行了认证");
UsernamePasswordToken userToken = (UsernamePasswordToken) token;
// 通过数据库查到登录用户
User user = userService.queryUserByName(userToken.getUsername());
if(user==null){
return null; //抛出异常 UnknownAccountException
}
// 密码认证 shiro来做
return new SimpleAuthenticationInfo("",user.getPwd(),"");
}
} -
运行测试,使用数据库的用户登录
Shiro请求授权实现
-
为数据库中的
user
表增加权限字段perms
并为其中两个用户添加user:add
和user:update
权限1
2
3-- 添加perms字段
alter table user
add perms varchar(100) null; -
修改
pojo
下的User
,添加perms
1
private String perms;
-
在IndexController中添加未授权提示方法
1
2
3
4
5
6// 未授权提示
public String unauthorized(){
return "您没有权限访问该页面";
} -
完善
UserRealm
中的授权和认证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
60package com.jokerdig.config;
import com.jokerdig.pojo.User;
import com.jokerdig.service.UserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
/**
* @author Joker大雄
* @data 2022/7/26 - 11:12
**/
// 自定以 Realm extends AuthorizingRealm
public class UserRealm extends AuthorizingRealm {
private UserService userService;
// 授权
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("执行了授权");
// 为用户授权 SimpleAuthorizationInfo
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
// 获取当前登录对象
Subject subject = SecurityUtils.getSubject();
// 通过认证中SimpleAuthenticationInfo第一个值获取
User currentUser = (User) subject.getPrincipal();
// 通过数据库中用户的权限信息来授权
info.addStringPermission(currentUser.getPerms());
return info;
}
// 认证
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("执行了认证");
UsernamePasswordToken userToken = (UsernamePasswordToken) token;
// 通过数据库查到登录用户
User user = userService.queryUserByName(userToken.getUsername());
if(user==null){
return null; //抛出异常 UnknownAccountException
}
// 通过当前用户获取session并把user传递到前端
Subject currentSubject = SecurityUtils.getSubject();
Session session = currentSubject.getSession();
session.setAttribute("loginUser",user);
// 密码认证 shiro来做
return new SimpleAuthenticationInfo(user,user.getPwd(),"");
}
} -
完善
ShiroConfig
中的页面拦截和未授权页面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
63package com.jokerdig.config;
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.LinkedHashMap;
import java.util.Map;
/**
* @author Joker大雄
* @data 2022/7/26 - 11:04
**/
public class ShiroConfig {
// ShiroFileFactoryBean
public ShiroFilterFactoryBean shiroFilterFactoryBean({ DefaultWebSecurityManager defaultWebSecurityManager)
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
//设置安全管理器
bean.setSecurityManager(defaultWebSecurityManager);
// 添加shiro内置过滤器
/*
anon 无需认证可以访问
authc 必须认证才能访问
user 必须拥有记住我功能才能使用
perms 拥有某个资源的权限才能访问
role 拥有某个角色权限才能访问
*/
Map<String,String> filterMap = new LinkedHashMap<>();
// 授权
// user:add user用户并且拥有add权限才能访问
filterMap.put("/user/add","perms[user:add]");
filterMap.put("/user/update","perms[user:update]");
bean.setFilterChainDefinitionMap(filterMap);
// 设置登录请求
bean.setLoginUrl("/toLogin");
// 设置未授权提示
bean.setUnauthorizedUrl("/noauth");
return bean;
}
// DefaultWebSecurityManager
public DefaultWebSecurityManager defaultWebSecurityManager({ UserRealm userRealm)
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 关联UserRealm
securityManager.setRealm(userRealm);
return securityManager;
}
// 创建Realm 对象 需要自定义
public UserRealm userRealm(){
return new UserRealm();
}
} -
运行测试
授权的用户可以访问对应权限页面,未授权则无法访问
Shiro整合Thymeleaf
-
在pom文件中引入整合shiro依赖
1
2
3
4
5
6<!-- shiro整合thymeleaf-->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency> -
在
ShiroConfig
中添加整合方法ShiroDialect
1
2
3
4
5// 整合ShiroDialect
public ShiroDialect getShiroDialect(){
return new ShiroDialect();
} -
在
IndexController
中添加注销登录方法1
2
3
4
5
6
7
8
9// logout
public String logout(){
// 注销登录
// 获取当前用户
Subject subject = SecurityUtils.getSubject();
subject.logout();
return "redirect:index";
} -
修改index.html页面
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<h1>首页</h1>
<div th:if="${session.loginUser==null}">
<a th:href="@{/toLogin}">登录</a>
</div>
<div th:if="${session.loginUser!=null}">
<a th:href="@{/logout}">注销</a>
</div>
<p th:text="${msg}"></p>
<hr>
<div shiro:hasPermission="user:add">
<a th:href="@{/user/add}">add</a>
</div>
<div shiro:hasPermission="user:update">
<a th:href="@{/user/update}">update</a>
</div>
</body>
</html> -
运行测试
根据用户权限展示对应的页面和注销功能的实现。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Hey,Joker!
评论
ValineTwikoo