Shiro和Spring MVC、Mybatis整合教程

前言

Apache Shiro 是Java的安全框架,提供了认证(Authentication)、授权(Authorization)、会话(Session)管理、加密(Cryptography)等功能,且Shiro与Spring Security等安全框架相比具有简单性、灵活性、支持细粒度鉴权、支持一级缓存等,还有Shiro不跟任何容器(Tomcat等)和框架(Sping等)捆绑,可以独立运行,这也造就了Shiro不仅仅是可以用在Java EE上还可以用在Java SE上

Shiro四大功能

在开始之前,首先了解一下Shiro的四大功能,俗话说“知己知彼百战不殆”。
image

认证

认证就是用户访问系统的时候,系统要验证用户身份的合法性,比如我们通常所说的“登录”就是认证的一种方式,只有登录成功了之后我们才能访问相应的资源。在Shiro中,我们可以将用户理解为Subject主体,在用户身份认证的时候,用户需要提供能证明他身份的信息,如用户名、密码等,用户所提供的这些用户名、密码则对应Shiro中的Principal、 Credentials,即在Subject进行身份认证的时候,需要提供相应的Principal、 Credentials,对应的代码如下:

1
2
3
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
Subject subject = SecurityUtils.getSubject();
subject.login(token); //提交认证

我们知道Http协议是无状态的,所以用户认证成功后怎么才能保持认证成功的状态呢?如果是我们开发的话一般都是登录成功后将Session储存在服务器,然后再将Session返回给用户,之后的请求用户都将这个Session带上,然后服务器根据用户请求携带的Session和服务器储存的Session进行比较来判断用户是否已认证。但是使用Shiro后,Shiro已经帮我们做好这个了(下面介绍的会话管理),是不是feel爽~

授权

授权可以理解为访问控制,在用户认证(登录)成功之后,系统对用户访问资源的权限进行控制,即确定什么用户能访问什么资源,如普通用户不能访问后台,但是管理员可以。在这里我们还需要认识几个概念,资源(Resource)、角色(Role)、权限(Permission),上面提到的Subject主体可以有多个角色,每个角色又对应多个资源的多个权限,这种基于资源的访问控制可以实现细粒度的权限。对主体设置角色、权限的代码如下:

1
2
3
4
5
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
// 添加用户的角色
authorizationInfo.addRoles(roleIdList);
// 添加用户的权限
authorizationInfo.addStringPermissions(resourceIdList);

如果要实现这样的授权功能,我们必定需要设计一个用户组、权限,给每个方法或者URL加上判断,是否当前登录的用户满足条件。但是使用Shiro后,Shiro也帮我们帮这些都做好了

会话管理

会话管理的会话即Session,所谓会话,即用户访问应用时保持的连接关系,在多次交互中应用能够识别出当前访问的用户是谁,且可以在多次交互中保存一些数据。如访问一些网站时登录成功后,网站可以记住用户,且在退出之前都可以识别当前用户是谁。在Shiro中,与用户有关的一切信息都可以通过Shiro的接口获得,和用户的会话Session也都由Shiro管理。如实现“记住我”或者“下次自动登录”的功能,如果要自己去开发的话,估计又得话不少时间。但是使用Shiro后,Shiro也帮我们帮这些都做好了

加密

用户密码明文保存是不是安全,应不应该MD5加密,是不是应该加盐,又要写密码加密的代码。 这些Shiro已经帮你做好了

Shiro三大核心概念

从整体概念上理解,Shiro的体系架构有三个主要的概念,Subject(主体),Security Manager (安全管理器)和 Realms (域)。
image

Subject主体

主体是当前正在操作的用户的特定数据集合。主体可以是一个人,也可以代表第三方服务,守护进程,定时任务或类似的东西,也就是几乎所有与该应用进行交互的事物。所有Subject都绑定到SecurityManager,与Subject的所有交互都会委托给 SecurityManager,可以把 Subject 认为是一个门面,SecurityManager 才是实际的执行者。

Security Manager安全管理器

安全管理器,即所有与安全有关的操作都会与SecurityManager交互,且它管理着所有Subject可以看出它是Shiro的核心,它负责与后边介绍的其他组件进行交互,如果学习过 SpringMVC,你可以把它看成DispatcherServlet前端控制器,一般来说,一个应用只会存在一个SecurityManager实例

Realms域

域,Shiro从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法,也需要从Realm得到用户相应的角色 / 权限进行验证用户是否能进行操作,即Realms作为Shiro与应用程序安全数据之间的“桥梁”。从这个意义上讲,Realm实质上是一个安全相关的DAO,它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。其中Realm有2个方法,doGetAuthenticationInfo用来认证,doGetAuthorizationInfo用来授权。

Spring、Spring MVC、Mybatis、Shiro集成

项目目录

image

添加依赖包

pox.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
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
<?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>shiro</groupId>
<artifactId>shiro</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>

<name>shiro 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>

<!--Sping核心依赖-->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.1.3.RELEASE</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.springframework/spring-web -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.1.3.RELEASE</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.3.RELEASE</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.3.RELEASE</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.3.RELEASE</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.springframework/spring-context-support -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.1.3.RELEASE</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.1.3.RELEASE</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.3.RELEASE</version>
<scope>test</scope>
</dependency>

<!--Mybatis依赖-->
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.2</version>
</dependency>

<!--MySQL连接驱动-->
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.13</version>
</dependency>


<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-core -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.0</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-web -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.4.0</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>

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


</dependencies>

<build>
<finalName>shiro</finalName>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>

创建数据库和实体类

为了减少篇幅,只做简单介绍,详情可以查看源码,数据库文件在本项目根目录。
image

  • resource表:资源表,有idname两个字段,分别对应资源id和权限。
  • role表:角色表,有idname两个字段,分别对应角色id和角色名。
  • role_resource表:角色资源权限表,有idroleidresid三个字段,分别对应自增id、角色id和资源id。
  • user表:用户表,有idusernamepassword三个字段,分别对应自增id、用户名和密码。
  • user_role表:有iduidrid三个字段,分别对应自增id、用户id、和角色id。

Dao层

AccountDao.java:

1
2
3
4
5
public interface AccountDao {
User findUserByUsername(String username);
List<Role> findRoleByUserId(int id);
List<Resource> findResourceByUserId(int id);
}

service层

AccountService.java:

1
2
3
4
5
6
public interface AccountService {
User findUserByUsername(String username);
List<Role> findRoleByUserId(int id);
List<Resource> findResourceByUserId(int id);
boolean login(User user);
}

AccountServiceImpl.java:

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
package com.shiro.service.impl;

import com.shiro.dao.AccountDao;
import com.shiro.entity.Role;
import com.shiro.entity.User;
import com.shiro.service.AccountService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;

/**
* @program: shiro
* @description:
* @author: Xue 8
* @create: 2019-02-01 15:37
**/
@Service
public class AccountServiceImpl implements AccountService {
@Resource
AccountDao accountDao;

/**
* @description: 根据用户名查找用户信息
* @param: [username]
* @return: com.shiro.entity.User
* @author: Xue 8
* @date: 2019/2/1
*/
@Override
public User findUserByUsername(String username) {
return accountDao.findUserByUsername(username);
}

@Override
public List<Role> findRoleByUserId(int id) {
return accountDao.findRoleByUserId(id);
}

@Override
public List<com.shiro.entity.Resource> findResourceByUserId(int id) {
return accountDao.findResourceByUserId(id);
}

public boolean login(User user){
// 获取当前用户对象subject
Subject subject = SecurityUtils.getSubject();
System.out.println("subject:" + subject.toString());
// 创建用户名/密码身份证验证Token
UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword());
System.out.println("token" + token);
try {
subject.login(token);
System.out.println("登录成功");
return true;
} catch (Exception e) {
System.out.println("登录失败" + e);
return false;
}
}
}

MyRealm.java

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
package com.shiro.service.impl;

import com.shiro.entity.Role;
import com.shiro.entity.User;
import com.shiro.service.AccountService;
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 javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
* @program: shiro
* @description:
* @author: Xue 8
* @create: 2019-02-01 15:16
**/

public class MyRealm extends AuthorizingRealm {
@Resource
AccountService accountService;

/**
* 身份认证的方法 认证成功获取身份验证信息
* 这里最主要的是user.login(token);这里有一个参数token,这个token就是用户输入的用户密码,
* 我们平时可能会用一个对象user来封装用户名和密码,shiro用的是token,这个是控制层的代码,还没到shiro,
* 当调用user.login(token)后,就交给shiro去处理了,接下shiro应该是去token中取出用户名,然后根据用户去查数据库,
* 把数据库中的密码查出来。这部分代码一般都是要求我们自定义实现,自定义一个realm,重写doGetAuthenticationInfo方法
**/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
// 获取用户输入的用户名和密码
// 实际上这个token是从UserResource面currentUser.login(token)传过来的
// 两个token的引用都是一样的
String username = (String) authenticationToken.getPrincipal();
// 密码要用字符数组来接受 因为UsernamePasswordToken(username, password) 储存密码的时候是将字符串类型转成字符数组的 查看源码可以看出
String password = new String((char[]) authenticationToken.getCredentials());
// 调用service 根据用户名查询用户信息
User user = accountService.findUserByUsername(username);
// String password = user.getPassword();
// 判断用户是否存在 不存在则抛出异常
if (user != null) {
// 判断用户密码是否匹配 匹配则不匹配则抛出异常
if (user.getPassword().equals(password)) {
// 登录成功 把用户信息储存在Session中
Session session = SecurityUtils.getSubject().getSession();
session.setAttribute("userSession", user);
session.setAttribute("userSessionId", user.getId());
// 认证成功 返回一个AuthenticationInfo的实现
return new SimpleAuthenticationInfo(username, password, getName());
} else {
System.out.println("密码不正确");
throw new IncorrectCredentialsException();
}
} else {
System.out.println("账号不存在");
throw new UnknownAccountException();
}
}

/**
* 授权的方法
* 1、subject.hasRole(“admin”) 或 subject.isPermitted(“admin”):自己去调用这个是否有什么角色或者是否有什么权限的时候;
*
* 2、@RequiresRoles("admin") :在方法上加注解的时候;
*
* 3、[@shiro.hasPermission name = "admin"][/@shiro.hasPermission]:在页面上加shiro标签的时候,即进这个页面的时候扫描到有这个标签的时候。
* 4、xml配置权限的时候也会走
**/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("授权");
// 从principalCollection获取用户信息
// 如果doGetAuthenticationInfo(user,password,getName()); 传入的是user类型的数据 那这里getPrimaryPrincipal获取到的也是user类型的数据
String username = (String) principalCollection.getPrimaryPrincipal();
User user = accountService.findUserByUsername(username);
// 获取该用户的所有角色
List<Role> roleList = accountService.findRoleByUserId(user.getId());
// 将角色的id放到一个String列表中 因为authorizationInfo.addRoles()方法只支持角色的String列表或者单个角色String
List<String> roleIdList = new ArrayList<String>();
for (Role role:roleList) {
roleIdList.add(role.getName());
}
// 获取该用户的所有权限
List<com.shiro.entity.Resource> resourceList = accountService.findResourceByUserId(user.getId());
List<String> resourceIdList = new ArrayList<String>();
// 将权限id放到一个String列表中 因为authorizationInfo.addRoles()方法只支持角色的String列表或者单个角色String
for (com.shiro.entity.Resource resource:resourceList) {
resourceIdList.add(resource.getName());
}
System.out.println("授权11");
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
// 添加用户的角色
authorizationInfo.addRoles(roleIdList);
// 添加用户的权限
authorizationInfo.addStringPermissions(resourceIdList);
return authorizationInfo;
}
}

controller层

AccountController.java

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

import com.shiro.entity.User;
import com.shiro.service.AccountService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

/**
* @program: shiro
* @description:
* @author: Xue 8
* @create: 2019-02-01 13:14
**/
@Controller
public class AccountController {
@Resource
AccountService accountService;
@Resource
HttpServletRequest servletRequest;

@RequestMapping(value = "/home")
public String home(){
return "home";
}

@RequestMapping(value = "/login", method = RequestMethod.GET)
public String getLogin(){
return "login";
}

@RequestMapping(value = "/login", method = RequestMethod.POST)
public String doLogin(@RequestParam(value = "username") String username,
@RequestParam(value = "password") String password){
User user = new User();
user.setUsername(username);
user.setPassword(password);
if (accountService.login(user)) {
return "/home";
}
return "/login";
}
}

GET方法访问/login的时候,会出现登录页面,输入账号密码点击登录数据将以POST方式提交给/login,如果账号密码匹配返回/home的页面,否则返回/login的页面。/home页面只有在登录且有权限的情况下才可以访问,未登录情况下访问会转跳/login页面,这个在Shiro的配置文件里面配置。

配置文件

applicationContext.xml:配置Spring

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
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
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">

<!--开启扫描注册-->
<context:component-scan base-package="com.shiro"></context:component-scan>

<!--读取properties配置-->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:jdbcConfig.properties"></property>
</bean>

<!--配置数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${driverClassName}"></property>
<property name="username" value="${username}"></property>
<property name="password" value="${password}"></property>
<property name="url" value="${url}"></property>
</bean>

<!--配置session工厂-->
<bean id="sessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
<property name="mapperLocations" value="classpath:mapping/*.xml"></property>
</bean>

<!--配置扫描mapping-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.shiro.dao"></property>
<property name="sqlSessionFactoryBeanName" value="sessionFactoryBean"></property>
</bean>
</beans>

spring-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
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="myRealm"></property>
</bean>

<bean id="myRealm" class="com.shiro.service.impl.MyRealm">
<!--关闭权限缓存 不然doGetAuthorizationInfo授权方法不执行-->
<property name="authorizationCachingEnabled" value="false"/>
</bean>

<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"></property>
<property name="successUrl" value="/success"></property>
<!--登录页面-->
<property name="loginUrl" value="/login"></property>
<property name="filterChainDefinitions">
<value>
<!--配置`/home`只有拥有`admin`角色的用户才可以访问-->
/home = authc,roles[admin]
</value>
</property>
</bean>

</beans>

这里需要注意的是 在配置Realm的时候,如果没用上缓存功能的话,需要将缓存关掉,不然进不到doGetAuthorizationInfo授权方法。

测试

打开http://localhost:8080/login登录页面,填写正确用户名和密码登录
image
登录成功 转跳成功页面
image
清除浏览器cookie之后(未登录状态),打开http://localhost:8080/home页面,自动转跳到了/login登录页面(即没有权限访问),登录账户,再次打开http://localhost:8080/home页面即可正常访问。

总结

这是我学习Shiro时候根据自己的情况记录下来的,希望对大家有所帮助,如果大家想对Shiro进一步研究的话,推荐大家看张开涛老师的《跟我学Shiro》,最后附上本项目的Github地址:https://github.com/xue8/Java-Demo/tree/master/shiro