目录
  1. 1. Spring整合shiro
    1. 1.1. 引言
    2. 1.2. shiro主要功能
      1. 1.2.1. 授权功能
      2. 1.2.2. 缓存功能
      3. 1.2.3. session管理功能(没啥用)
      4. 1.2.4. rememberMe功能
    3. 1.3. 使用maven管理
    4. 1.4. resources资源文件配置
    5. 1.5. webapp配置
    6. 1.6. java源文件
      1. 1.6.1. com.myShiro.controller包
    7. 1.7. com.myShiro.pojo包
    8. 1.8. com.myShiro.realm包
    9. 1.9. com.myShiro.filter
    10. 1.10. 测试
Spring整合shiro

Spring整合shiro

引言

shiro在Spring中最大的作用是授权

shiro主要功能

授权功能
  • 代码式授权
    需要在自己的realm中写入授权代码
  • 注解式授权
    需要在spring-mvc.xml中配置注解授权支持
    并且在controller中设置注解
  • jsp页面授权
    需要在jsp页面中导入shiro的授权标签库
缓存功能
  • 解决问题
    我们在项目中每一次授权都要去查询数据库,这样的话数据库的压力就会相当的大
  • 解决方法
    shiro提供了cache缓存机制,这样会将第一次授权查询数据库所得的数据缓存,以便以后授权使用
  • 需求
    导入ehcache依赖,配置ehcache.xml文件,配置bean-shiro.xml文件
session管理功能(没啥用)
rememberMe功能
  • 解决问题
    我们输入用户信息登录后,不会记住我们的用户信息,这样我们在段时间后登录就需要重新输入数据
  • 解决方法
    shiro提供了rememberMe功能,使得用户信息能够保存一定时间
  • 需求
    配置bean-shiro.xml文件,编写测试页面

使用maven管理

  • 配置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
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
<?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.shiro.test</groupId>
<artifactId>myShiro</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>

<name>myShiro Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>

<!--导入shiro的相关的包 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-quartz</artifactId>
<version>1.3.2</version>
</dependency>

<!--导入Spring的相关包 -->

<!--导入我们的Servlet的API -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>

<!--导入我们jstl的标签库的包 -->
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>javax.servlet.jsp.jstl-api</artifactId>
<version>1.2.1</version>
</dependency>

<!-- https://mvnrepository.com/artifact/javax.servlet/jsp-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>org.apache.taglibs</groupId>
<artifactId>taglibs-standard-impl</artifactId>
<version>1.2.5</version>
</dependency>

<!--导入我们的mybatis运行的时候的一些依赖包日志相关的 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!--导入的是日志相关的包 -->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<!--带入cglib代理的包 -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.4</version>
</dependency>
<!--引入junit类 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>

<!--在使用Spring的时候没有这个包的时候是要报错的-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>

<!--导入我们Spring的相关包 -->

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>

<!--介入aspectj的相关包 -->
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.11</version>
</dependency>


<!--配置fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>

<!--简化实体类的编写,不用写setget方法-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.6</version>
<scope>provided</scope>
</dependency>

<!--引入缓存包-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.3.2</version>
</dependency>
</dependencies>


</project>

resources资源文件配置

  • bean-shiro.xml配置(配置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
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
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">

<!--1. 配置shiro过滤,这里的id需要与web.xml中保持一致-->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!--登录失败则跳转到下面这个地址-->
<property name="loginUrl" value="/login.action"></property>
<!--注入SecurityManager对象-->
<property name="securityManager" ref="defaultWebSecurityManager"></property>

<property name="unauthorizedUrl" value="/refuse.jsp"></property>
<!--定义过滤链-->
<property name="filterChainDefinitions">
<value>
/favicon.ico = anon
<!--释放静态资源-->
/css/** = anon
/js/** = anon
<!--配置remmberMe-->
/index.jsp = user
<!--配置过滤器授权,这个路径的范文用户必须拥有userManager和seller权限-->
/filterAuth.action = perms[userManager]
/filterAuth.action = roles[seller]
<!--退出登录-->
/logout.action = logout
<!--表示所有资源需要认证后才能通过(需要写到最后)-->
/** = authc
</value>
</property>
</bean>


<!--2. 配置安全管理器-->
<bean id="defaultWebSecurityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="myRealm"></property>
<!--注入缓存的管理器-->
<property name="cacheManager" ref="ehCacheManager"></property>

<!--注入sessionManager的管理器(没有用)-->
<!-- <property name="sessionManager" ref="sessionManager"></property>-->
<property name="rememberMeManager" ref="rememberMeManager"></property>
</bean>

<!--声明自己的realm对象-->
<bean id="myRealm" class="com.myShiro.realm.MyRealm"></bean>



<!--3. 配置缓存管理器 -->
<bean id="ehCacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<property name="cacheManager" ref="cacheManager"></property>
</bean>
<!--配置缓存-->
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<!--缓存是否共享-->
<property name="shared" value="true"></property>
<property name="configLocation" value="classpath:ehcache.xml"></property>
</bean>


<!--配置session管理器-->
<!-- <bean id="sessionManager" class="org.apache.shiro.session.mgt.DefaultSessionManager">-->
<!--配置session过期之后是否需要删除-->
<!-- <property name="deleteInvalidSessions" value="true"></property>-->
<!--配置session的超时时间-->
<!-- <property name="globalSessionTimeout" value="259200"></property>-->
<!-- </bean>-->

<!--配置记住我管理器-->
<bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
<!--注入cookie-->
<property name="cookie" ref="cookie"></property>
</bean>

<!--配置cookie-->
<bean id="cookie" class="org.apache.shiro.web.servlet.SimpleCookie">
<!--调用有参构造,给存储的cookie取名-->
<constructor-arg name="name" value="rememberMe"></constructor-arg>
<!--cookie最大生效时间-->
<property name="maxAge" value="2596000"></property>
</bean>
</beans>
  • spring-mvc.xml配置(配置springmvc)
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
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">

<!--shiro注解授权配置-->
<bean id="authorizationAttributeSourceAdvisor" class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<!--注入安全管理器对象,使得授权有安全支持-->
<property name="securityManager" ref="defaultWebSecurityManager"></property>
</bean>
<!--开启aop,代理类-->
<aop:config proxy-target-class="true"></aop:config>

<!--扫描控制器-->
<context:component-scan base-package="com.myShiro.controller"></context:component-scan>

<!--加载注解驱动-->
<mvc:annotation-driven></mvc:annotation-driven>
</beans>
  • ehcache.xml(配置缓存)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd">

<!--缓存到硬盘的位置-->
<diskStore path="/tmp"/>
<!--配置的是默认所有的缓存数据的生命周期-->
<defaultCache
maxElementsInMemory="1000"
maxElementsOnDisk="10000000"
eternal="false"
overflowToDisk="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</defaultCache>
</ehcache>

webapp配置

  • web.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
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
<display-name>Archetype Created Web Application</display-name>

<!--配置Spring-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:bean-*.xml</param-value>
</context-param>

<!--配置shiro的过滤器-->
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<!--管理生命周期-->
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<!--配置spingmvc-->
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:sping-mvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
</web-app>

java源文件

com.myShiro.controller包
  • 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
package com.myShiro.controller;

import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class UserController {

/**
* 认证出错时跳转到login.jsp页面
* 收集错误信息
* @return
*/
@RequestMapping("login")
public String login(){
return "/login.jsp";
}


@RequestMapping("filterAuth")
public String filterAuth(){
System.out.println("过滤器授权已经执行");
return "/first.jsp";
}

/**
* 使用注解授权
* 当前方法必须要具有userManager和seller权限才能访问
*/
@RequestMapping("annotationAuth")
@RequiresPermissions("userManager")
@RequiresRoles("seller")
public String annotationAuth(){
System.out.println("过滤器已经授权...");
return "/first.jsp";
}
}
  • IndexController
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
package com.myShiro.controller;

import com.myShiro.pojo.User;
import org.apache.shiro.SecurityUtils;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class IndexController {

/**
* 登录成功跳转到首页
*/
@RequestMapping("jumpIndexPage")
public String jumpIndexPage(Model model){
//取出登录用户
User user = (User) SecurityUtils.getSubject().getPrincipal();
System.out.println("取出登录用户:"+user);
//将登录用户对象放入域对象中
model.addAttribute("user",user);

//带值跳转到index.jsp页面
return "/index.jsp" ;
}
}

com.myShiro.pojo包

  • User
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.myShiro.pojo;

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

import java.io.Serializable;

@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class User implements Serializable {
private int id ;
private String username ;
private String password ;

}

com.myShiro.realm包

  • MyRealm
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
package com.myShiro.realm;

import com.myShiro.pojo.User;
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.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

import java.util.HashSet;
import java.util.Set;

public class MyRealm extends AuthorizingRealm {

/**
* 重写Class类中的getName方法
* @return
*/
@Override
public String getName(){
return "MyRealm" ;
}

/**
* 授权的方法
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("我是realm的授权...");
//使用代码进行授权
Set<String> perms = new HashSet<>();
perms.add("userManager");
perms.add("adManager");
perms.add("deptManager");
perms.add("employeeManager");

Set<String> roles = new HashSet<>();
roles.add("seller");
roles.add("employee");

SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
//将集合中的权限字符串加入authorizationInfo对象中
authorizationInfo.setStringPermissions(perms);
authorizationInfo.setRoles(roles);
return authorizationInfo ;
}

/**
* 认证的方法
* @param authenticationToken
* @return 返回的是一个简单认证信息对象
* @throws AuthenticationException
*
* userName: 输入的authenticationToken对象,也就是用户账户名
* user.getPassword: 证书,也就是用户密码,这是从数据库中查询出来用于匹配的
* getName():获取的是当前realm类的类名
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//从令牌中获取用户名
String userName = (String) authenticationToken.getPrincipal();
System.out.println("输入的用户名:"+userName);
//通过用户名查找对象(如果输入的用户名与指定的用户名不相同则授权失败)
if(!("rack".equals(userName))){
System.out.println("没找到");
return null ;
}

//在这里创建一个用户对象代表从数据库中查找数据
User user = new User(1,"rack","123");
System.out.println("数据库中用户信息:"+user);
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), getName());
System.out.println("info:"+info);
return info ;
}
}

com.myShiro.filter

  • MyFormAuthenticationFilter(表单验证过滤器)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.myShiro.filter;

import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.util.WebUtils;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class MyFormAuthenticationFilter extends FormAuthenticationFilter {

@Override
protected boolean onLoginSuccess(AuthenticationToken token, Subject subject,
ServletRequest request, ServletResponse response) throws Exception{
//清空请求
WebUtils.getAndClearSavedRequest(request);
//重定向页面
WebUtils.issueRedirect(request , response , "/first.action");
return false ;
}
}

测试

  • 测试登录
1

  • 测试过滤器授权
1

  • 测试注解授权
1

文章作者: rack-leen
文章链接: http://yoursite.com/2019/06/12/Java/Java%E6%A1%86%E6%9E%B6/Shiro/Spring%E6%95%B4%E5%90%88shiro/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 rack-leen's blog
打赏
  • 微信
  • 支付宝

评论