第四章:shiro 集成spring boot

未集成环境准备

创建UserController控制器,准备增删改查及导出用户数据的方法

测试未集成环境下的效果:全部方法皆可正常访问

UserController

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.bdqn.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/user")
public class UserController {

/**
* 去到登录页面
* @return
*/
@RequestMapping("/tologin")
public String toLogin(){
return "login";
}

@ResponseBody
@RequestMapping("/userAdd")
public String userAdd(){
return "userAdd";
}
@ResponseBody
@RequestMapping("/userUpdate")
public String userUpdate(){
return "userUpdate";
}
@ResponseBody
@RequestMapping("/userDelete")
public String userDelete(){
return "userDelete";
}
@ResponseBody
@RequestMapping("/userQuery")
public String userQuery(){
return "userQuery";
}

@ResponseBody
@RequestMapping("/userExport")
public String userExport(){
return "userExport";
}
}

login.html

在templates目录下添加login.html页面(thymeleaf模板)

注意:需要在pom.xml文件中添加thymeleaf的依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>用户登录</title>
</head>
<body>
<form action="/user/login" method="post">
用户名:<input type="text" name="username"/><br/>
密码:<input type="password" name="userpwd"/><br/>
<input type="submit" value="登录"/>
</form>
</body>
</html>

shiro集成spring boot

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
<!-- springboot web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- tomcat -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</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>

<!-- mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>

<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>

<!-- shiro与spring整合依赖 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.2</version>
</dependency>

<!-- thymeleaf -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

<!--shrio和thymeleaf集成的扩展依赖,为了能在页面上使用xsln:shrio的标签 -->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>

<!-- 热部署 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>

application.properties

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#加载驱动
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#数据库连接路径
spring.datasource.url=jdbc:mysql://localhost:3306/db_shiro?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
#数据库用户名
spring.datasource.username=root
#数据库密码
spring.datasource.password=root
#thymeleaf
spring.thymeleaf.cache=false
#mybatis
mybatis.mapper-locations=classpath:mapper/*Mapper.xml
#日志
logging.level.com.bdqn.dao=debug

复制代码

将shiro03spring项目中的代码复制到本项目中,复制的内容有:entity,dao,service,controller,exception,realm,vo等包下的代码文件。

注意:将shiro03spring项目中的映射文件复制到resources目录下的mapper文件夹中

image-20191209165012028

ShiroConfiguration

在config包下添加ShiroConfiguration配置类

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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package com.bdqn.config;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.bdqn.realm.UserRealm;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.DelegatingFilterProxy;

import java.util.LinkedHashMap;
import java.util.Map;


@Configuration
public class ShiroConfiguration {


private static final String SHIRO_DIALECT = "shiroDialect";
private static final String SHIRO_FILTER = "shiroFilter";
private String hashAlgorithmName = "md5";// 加密方式
private int hashIterations = 2;// 散列次数

/**
* 声明凭证匹配器
*/
@Bean("credentialsMatcher")
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
credentialsMatcher.setHashAlgorithmName(hashAlgorithmName);//设置凭证方式
credentialsMatcher.setHashIterations(hashIterations);//设置散列次数
return credentialsMatcher;
}

/**
* 注入自定义的UserRealm
* @return
*/
@Bean
public UserRealm getUserRealm(CredentialsMatcher credentialsMatcher){
UserRealm userRealm = new UserRealm();
//注入凭证匹配器
userRealm.setCredentialsMatcher(credentialsMatcher);
return userRealm;
}

/**
* 创建DefaultWebSecurityManager对象,关联自定义的UserRealm对象
* @param userRealm
* @return
*/
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(UserRealm userRealm){
//创建DefaultWebSecurityManager对象
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
//关联自定义realm
defaultWebSecurityManager.setRealm(userRealm);
//返回DefaultWebSecurityManager对象
return defaultWebSecurityManager;
}


/**
* 创建ShiroFilterFactoryBean对象,设置安全管理器
* @param securityManager
* @return
*/
@Bean(SHIRO_FILTER)
public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager securityManager){
//创建ShiroFilterFactoryBean对象
ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
//设置安全管理器
factoryBean.setSecurityManager(securityManager);
//身份验证失败要去到登录页面
//如果不设置loginUrl,则默认找login.jsp页面
factoryBean.setLoginUrl("/user/tologin");
//设置过滤器链
Map<String,String> filterChainDefinitionsMap = new LinkedHashMap<String,String>();
//放行路径(匿名访问)
filterChainDefinitionsMap.put("/resources/**","anon");//静态资源
filterChainDefinitionsMap.put("/user/login","anon");//登录请求
filterChainDefinitionsMap.put("/user/tologin","anon");//去到登录页面
filterChainDefinitionsMap.put("/favicon.ico","anon");//去到登录页面
//退出
filterChainDefinitionsMap.put("/logout","logout");
//拦截请求
filterChainDefinitionsMap.put("/**","authc");
//将过滤器链设置到shiroFilterFactoryBean对象中
factoryBean.setFilterChainDefinitionMap(filterChainDefinitionsMap);
return factoryBean;
}


/**
* 注册shiro的委托过滤器,相当于之前在web.xml里面配置的
*
* @return
*/
@Bean
public FilterRegistrationBean<DelegatingFilterProxy> delegatingFilterProxy() {
FilterRegistrationBean<DelegatingFilterProxy> filterRegistrationBean = new FilterRegistrationBean<DelegatingFilterProxy>();
DelegatingFilterProxy proxy = new DelegatingFilterProxy();
proxy.setTargetFilterLifecycle(true);
proxy.setTargetBeanName(SHIRO_FILTER);
filterRegistrationBean.setFilter(proxy);
return filterRegistrationBean;
}
/* 加入注解的使用,不加入这个注解不生效--开始 */
/**
*
* @param securityManager
* @return
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}

@Bean
public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
advisorAutoProxyCreator.setProxyTargetClass(true);
return advisorAutoProxyCreator;
}
/* 加入注解的使用,不加入这个注解不生效--结束 */

/**
* 为了能在html页面引用shiro标签,上面两个函数必须添加,不然会报错
* @return
*/
@Bean(name = SHIRO_DIALECT)
public ShiroDialect shiroDialect() {
return new ShiroDialect();
}
}

index.html

需要引入shiro命名空间

xmlns:shiro=”http://www.pollix.at/thymeleaf/shiro"

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<h2 shiro:hasPermission="user:add"><a href="/user/userAdd">添加用户</a></h2>
<h2 shiro:hasPermission="user:delete"><a href="/user/userDelete">删除用户</a></h2>
<h2 shiro:hasPermission="user:update"><a href="/user/userUpdate">修改用户</a></h2>
<h2 shiro:hasPermission="user:query"><a href="/user/userQuery">查询用户</a></h2>
<h2 shiro:hasPermission="user:export"><a href="/user/userExport">导出用户</a></h2>
<h2><a href="/logout">退出系统</a></h2>
</body>
</html>