SpringBoot+Mybatis框架整合Shiro权限管理

一、前言

​ 之前曾分享过一个关于shiro的认证原理的文章,分享了一下shiro的认证流程与shiro中的名词解释,其实shiro作为一款轻量级框架,被应用在各种中小型及大型企业的登录认证和用户授权的模块,有小伙伴称,在用SpringBoot框架,之前用过xml方式进行配置shiro框架,问我如何使用SpringBoot+注解来进行shiro的配置,我整理了文章,供大家参考

二、搭建shiro框架

1.首先搭建SpringBoot基础工程和Mybatis整合,此步骤之前讲解过,可自行前往之前的帖子中查看

SpringBoot工程搭建

SpringBoot整合Mybatis

2.引入shiro-spring的依赖包,完整的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
<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.yang.study.shiro</groupId>
<artifactId>SpringBootShiro</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>SpringBootShiro</name>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
</parent>
<!-- 添加相关依赖 -->
<dependencies>
<!-- 添加web支持的starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- spingBoot整合Mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.2.0</version>
</dependency>
<!-- 数据源 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.29</version>
</dependency>
<!-- mysql驱动包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- 好用的分页插件 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>4.1.0</version>
</dependency>
<!-- 整合shiro -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.3.2</version>
</dependency>
</dependencies>
<!-- 添加编译和打包的相关插件 -->
<build>
<!-- 打包的最新插件 -->
<finalName>SpringBootShiro</finalName>
<!-- 添加Spring boot编译插件 -->
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

3.创建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
CREATE TABLE `permission` (
`id` bigint(20) NOT NULL,
`permission` varchar(200) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='权限表';
-- 插入数据
INSERT INTO `permission` VALUES ('1', 'user:queryUserAll');
INSERT INTO `permission` VALUES ('2', 'user:queryById');

DROP TABLE IF EXISTS `role`;
CREATE TABLE `role` (
`id` bigint(11) NOT NULL,
`role_name` varchar(40) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='角色表';
-- 插入数据
INSERT INTO `role` VALUES ('1', 'admin');
INSERT INTO `role` VALUES ('2', 'devlop');

DROP TABLE IF EXISTS `role_permission`;
CREATE TABLE `role_permission` (
`role_id` bigint(20) DEFAULT NULL,
`permission_id` bigint(20) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='角色权限表';
-- 插入数据
INSERT INTO `role_permission` VALUES ('1', '1');
INSERT INTO `role_permission` VALUES ('1', '2');
INSERT INTO `role_permission` VALUES ('2', '2');

DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` bigint(20) NOT NULL,
`name` varchar(40) DEFAULT NULL,
`password` varchar(40) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户表';
-- 插入数据
INSERT INTO `user` VALUES ('1', 'admin', '123456');
INSERT INTO `user` VALUES ('2', 'yang', '123456');

DROP TABLE IF EXISTS `user_role`;
CREATE TABLE `user_role` (
`user_id` bigint(20) NOT NULL,
`role_id` bigint(20) DEFAULT NULL,
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户角色表';
-- 插入数据
INSERT INTO `user_role` VALUES ('1', '1');

4.生成所对应的实体bean对象(可自己编写,也可使用mybatis自动生成器

User对象实体类
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
package com.yang.bean;

import java.io.Serializable;
import java.util.List;

public class User implements Serializable {
private Long id;

private String name;

private String password;

private List<Role> roles;

private static final long serialVersionUID = 1L;

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name == null ? null : name.trim();
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password == null ? null : password.trim();
}

public List<Role> getRoles() {
return roles;
}

public void setRoles(List<Role> roles) {
this.roles = roles;
}
}
角色Role对象实体类
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
package com.yang.bean;

import java.io.Serializable;
import java.util.List;

public class Role implements Serializable {
private Long id;

private String roleName;

private User user;

private List<Permission> permissions;

private static final long serialVersionUID = 1L;

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getRoleName() {
return roleName;
}

public void setRoleName(String roleName) {
this.roleName = roleName == null ? null : roleName.trim();
}

public User getUser() {
return user;
}

public void setUser(User user) {
this.user = user;
}

public List<Permission> getPermissions() {
return permissions;
}

public void setPermissions(List<Permission> permissions) {
this.permissions = permissions;
}
}
权限表对象Permission实体类
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
package com.yang.bean;

import java.io.Serializable;

public class Permission implements Serializable {
private Long id;

private String permission;

private Role role;

private static final long serialVersionUID = 1L;

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getPermission() {
return permission;
}

public void setPermission(String permission) {
this.permission = permission == null ? null : permission.trim();
}

public Role getRole() {
return role;
}

public void setRole(Role role) {
this.role = role;
}
}
其他两个关系表可根据自己需求自主编写,因为我用的生成器,所以所有表的实体都生成了,结构如下

5.编写用户登录接口及数据库映射文件,根据用户名查询出角色和权限列表,供后期shiro登录来用

UserMapper类,面向接口开发的Mybatis接口
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
package com.yang.dao;

import com.yang.bean.User;
import java.util.List;

public interface UserMapper {
int deleteByPrimaryKey(Long id);

int insert(User record);

User selectByPrimaryKey(Long id);

List<User> selectAll();

int updateByPrimaryKey(User record);

/**
* 根据名称查询
* @param name
* @return
*/
User selectByName(String name);

/**
* 登录接口
* @param user
* @return
*/
User login(User user);
}
UserMapper.xml,xml映射文件及sql编写文件,编写五表查询语句
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
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.yang.dao.UserMapper" >
<resultMap id="BaseResultMap" type="com.yang.bean.User" >
<id column="id" property="id" jdbcType="BIGINT" />
<result column="name" property="name" jdbcType="VARCHAR" />
<result column="password" property="password" jdbcType="VARCHAR" />
<collection property="roles" ofType="com.yang.bean.Role">
<id column="roleId" property="id" jdbcType="BIGINT"/>
<result column="roleName" property="roleName" jdbcType="VARCHAR"/>
<collection property="permissions" ofType="com.yang.bean.Permission">
<id column="pId" property="id" jdbcType="BIGINT"/>
<result column="permission" property="permission" jdbcType="VARCHAR"/>
</collection>
</collection>
</resultMap>
<delete id="deleteByPrimaryKey" parameterType="java.lang.Long" >
delete from user
where id = #{id,jdbcType=BIGINT}
</delete>
<insert id="insert" parameterType="com.yang.bean.User" >
<selectKey resultType="java.lang.Long" keyProperty="id" order="AFTER" >
SELECT LAST_INSERT_ID()
</selectKey>
insert into user (`name`, `password`)
values (#{name,jdbcType=VARCHAR}, #{password,jdbcType=VARCHAR})
</insert>
<update id="updateByPrimaryKey" parameterType="com.yang.bean.User" >
update user
set `name` = #{name,jdbcType=VARCHAR},
`password` = #{password,jdbcType=VARCHAR}
where id = #{id,jdbcType=BIGINT}
</update>
<select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Long" >
select id, `name`, `password`
from user
where id = #{id,jdbcType=BIGINT}
</select>
<select id="selectAll" resultMap="BaseResultMap" >
select id, `name`, `password`
from user
</select>
<select id="selectByName" parameterType="java.lang.String" resultMap="BaseResultMap">
SELECT
u.id id,
u.`name`,
u.`password`,
r.id roleId,
r.role_name roleName,
p.id pId,
p.permission
FROM
`user` AS u LEFT JOIN
user_role AS ur on u.id=ur.user_id LEFT JOIN role r ON ur.role_id=r.id LEFT JOIN role_permission rp ON r.id= rp.role_id LEFT JOIN permission p ON rp.permission_id=p.id
where u.`name` = #{name}
</select>
<select id="login" parameterType="com.yang.bean.User" resultMap="BaseResultMap">
SELECT
u.id id,
u.`name`,
u.`password`,
r.id roleId,
r.role_name roleName,
p.id pId,
p.permission
FROM
`user` AS u LEFT JOIN
user_role AS ur on u.id=ur.user_id LEFT JOIN role r ON ur.role_id=r.id LEFT JOIN role_permission rp ON r.id= rp.role_id LEFT JOIN permission p ON rp.permission_id=p.id
where u.`name` = #{name} and u.password=#{password}
</select>
</mapper>

6.此处编写了两个工具类,分别是:一个全局数据统一返回的类,一个用来定义常量的类,内容如下

1
2
3
4
5
6
7
8
9
10
package com.yang.util;

public class Constant {
//统一返回码--成功
public static String SUCCESS_RETUEN_CODE="0";
//统一返回码--失败
public static String FAILURE_RETUEN_CODE="-9999";
//统一返回码--已存在
public static String HASE_RETUEN_CODE="1";
}
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
package com.yang.bean;

public class ResultObject<T> {
private String code;
private String msg;
private T data;
private Long count;

public Long getCount() {
return count;
}
public void setCount(Long count) {
this.count = count;
}

public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}

7.开始配置shiro的自定义relam来做认证,MyShiroRealm,具体查询数据库的服务类,自己编写

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
package com.yang.shiro;
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 org.springframework.beans.factory.annotation.Autowired;

import com.yang.bean.Permission;
import com.yang.bean.Role;
import com.yang.bean.User;
import com.yang.service.IUserService;

//实现AuthorizingRealm接口用户用户认证
public class MyShiroRealm extends AuthorizingRealm{

//用于用户查询
@Autowired
private IUserService userService;

//角色权限和对应权限添加
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//获取登录用户名
String name= (String) principalCollection.getPrimaryPrincipal();
//查询用户名称
User user = userService.getUserByName(name);
//添加角色和权限
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
for (Role role:user.getRoles()) {
//添加角色
simpleAuthorizationInfo.addRole(role.getRoleName());
for (Permission permission:role.getPermissions()) {
//添加权限
simpleAuthorizationInfo.addStringPermission(permission.getPermission());
}
}
return simpleAuthorizationInfo;
}

//用户认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) {
//加这一步的目的是在Post请求的时候会先进认证,然后在到请求
if (authenticationToken.getPrincipal() == null) {
return null;
}
//获取用户信息
String name = authenticationToken.getPrincipal().toString();
User user = userService.getUserByName(name);
if (user == null) {
//这里返回后会报出对应异常
return null;
} else {
//这里验证authenticationToken和simpleAuthenticationInfo的信息
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(name, user.getPassword().toString(), getName());
return simpleAuthenticationInfo;
}
}
}

8.配置shiro的过滤器到spring的容器中,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
package com.yang.shiro;

import java.util.HashMap;
import java.util.Map;

import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
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.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ShiroConfiguration {

//将自己的验证方式加入容器
@Bean
public MyShiroRealm myShiroRealm() {
MyShiroRealm myShiroRealm = new MyShiroRealm();
return myShiroRealm;
}

//权限管理,配置主要是Realm的管理认证
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myShiroRealm());
return securityManager;
}

//Filter工厂,设置对应的过滤条件和跳转条件
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
Map<String,String> map = new HashMap<String, String>();
//登入
map.put("/user/login", "anon");
//静态资源
map.put("/assets/**", "anon");
//404界面
map.put("/404.html","anon");
//登出
map.put("/user/logout","logout");
//对所有用户认证
map.put("/**","authc");
//登录
shiroFilterFactoryBean.setLoginUrl("/login.html");
//首页
shiroFilterFactoryBean.setSuccessUrl("/index.html");
//错误页面,认证不通过跳转
shiroFilterFactoryBean.setUnauthorizedUrl("/error.html");
//登录接口

shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return shiroFilterFactoryBean;
}

//加入注解的使用,不加入以下三个这个注解不生效
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
@Bean
public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}

@Bean
public static DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator(){
return new DefaultAdvisorAutoProxyCreator();
}
}

9.由于shiro在登录认证时,如果用户验证失败,会有相关的异常抛出,编写全局异常处理器(ControllerAdvice),来处理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
package com.yang.excpetion;

import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
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.RestController;
import com.yang.bean.ResultObject;
import com.yang.util.Constant;

/**
* 自定义全局异常捕获
*
* @author yzx96
*
*/
@RestController
@ControllerAdvice
public class MyExceptionHandler {

/**
* 用户不存在异常
* @return
*/
@ExceptionHandler(UnknownAccountException.class)
public ResultObject<Object> unknownAccountException() {
ResultObject<Object> rs = new ResultObject<Object>();
rs.setCode(Constant.FAILURE_RETUEN_CODE);
rs.setMsg("用户不存在");
return rs;
}

/**
* 验证异常
* @return
*/
@ExceptionHandler(IncorrectCredentialsException.class)
public ResultObject<Object> incorrectCredentialsException() {
ResultObject<Object> rs = new ResultObject<Object>();
rs.setCode(Constant.FAILURE_RETUEN_CODE);
rs.setMsg("密码错误");
return rs;
}


@ExceptionHandler(UnauthorizedException.class)
public ResultObject<Object> nauthorizedException() {
ResultObject<Object> rs = new ResultObject<Object>();
rs.setCode(Constant.FAILURE_RETUEN_CODE);
rs.setMsg("当前用户没有权限");
return rs;
}
}

10.编写登录,登出入口,并给查询所有用户的接口中加上角色要求

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
package com.yang.controller;
import java.util.List;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.yang.bean.ResultObject;
import com.yang.bean.User;
import com.yang.service.IUserService;
import com.yang.util.Constant;

/**
* 用戶访问
* @author yzx96
*
*/
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private IUserService userService;
/**
* 根据用户姓名获取权限和角色信息
* @return
*/

@RequestMapping("/queryByName")
public User getUserByName() {
return userService.getUserByName("admin");
}
/**
* 登录
* @param user
* @return
*/
@RequestMapping(value = "/login")
public ResultObject<User> login(User user){
ResultObject<User> rs = new ResultObject<User>();
//添加用户认证信息
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(user.getName(),user.getPassword());
//进行验证,这里可以捕获异常,然后返回对应信息
subject.login(usernamePasswordToken);
rs.setCode(Constant.SUCCESS_RETUEN_CODE);
rs.setMsg("成功登陆");
user.setPassword("你想知道吗,我删了 哈哈");
rs.setData(user);
return rs;
}
@RequestMapping(value = "/logout")
public ResultObject<String> user(){
ResultObject<String> rs = new ResultObject<String>();
//添加用户认证信息
Subject subject = SecurityUtils.getSubject();
subject.logout();
rs.setCode(Constant.SUCCESS_RETUEN_CODE);
rs.setMsg("成功退出");
return rs;
}
//必须有admin角色
@RequiresRoles("admin")
@RequestMapping("/queryUserAll")
public ResultObject<List<User>> queryUserAll() {
ResultObject<List<User>> rs = new ResultObject<List<User>>();
rs.setCode(Constant.SUCCESS_RETUEN_CODE);
List<User> list=userService.getAllUser();
rs.setData(list);
rs.setCount(Long.valueOf(list.size()));
return rs;
}

}

11.在public文件夹下编写登录界面和主界面,将登录界面和登录信息配置到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
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>

</head>
<body>
<h2>shiro测试登录</h2>
<form id="form1" style="line-height: 50px;">
姓名:<input type="text" id="name" name="name" /><br/>
密码:<input type="password" id="pass" name="password /"><br/>
<input type="button" id="login" value="登陆一下下吧" />
</form>
<script src="assets/js/jquery-3.3.1.min.js"></script>
<script type="text/javascript">
$("#login").on("click",login);
function login(){
var data={
"name":$("#name").val(),
"password":$("#pass").val()
};
$.ajax({
//几个参数需要注意一下
type: "POST",//方法类型
dataType: "json",//预期服务器返回的数据类型
url: "/user/login" ,//url
data: data,
success: function (result) {
if(result.code=="0"){
location.href="/index.html";
}else{
alert(result.msg);
}

},
error : function() {
alert("登录失败");
}
});
}
</script>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>主页</title>
<script src="assets/js/aJaxUtil.js"></script>
<script src="assets/js/jquery-3.3.1.min.js"></script>
</head>
<body>
<h2>这里是主页</h2>
</body>
<script type="text/javascript">
</script>
</html>

12.全部项目结构如下

13.在boot中启动项目,开始测试,启动文件如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.yang.boot;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication //SpringBoot启动类注解
@EnableAutoConfiguration //开启自动化配置
@ComponentScan("com.yang") //类似于Spring的基础类扫描包,用来扫描实体,接口和控制器
@MapperScan("com.yang.dao") //mybatis的接口扫描包
public class StartShiroApplication {
public static void main(String[] args) {
SpringApplication.run(StartShiroApplication.class, args);
}
}

14.启动后,访问项目地址,自动跳转到login界面,输入其他界面地址,都会跳转到login界面,证明shiro拦截生效了

15.输入不存在的用户名,第二次输入错误的密码,返回信息如下

两个返回的信息证明,全局异常捕获拦截到了用户认证的两个异常,并且生效了

16.测试登录后的权限,由于在查询所有用户的权限上加上了必须为admin的角色

17.分别使用admin角色用户admin,devlop用户yang来登录测试queryUserAll接口(用户在sql脚本中插入并赋权的)

接口返回标识权限认证的保存信息已经被拦截掉,并且接口的权限认证已经生效

18.此时,shiro的认证和授权已经生效,整合完毕,源码点我获取,有问题欢迎来踩,附上常用注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
RequiresAuthentication:
使用该注解标注的类,实例,方法在访问或调用时,当前Subject必须在当前session中已经过认证。

RequiresGuest:
使用该注解标注的类,实例,方法在访问或调用时,当前Subject可以是“gust”身份,不需要经过认证或者在原先的session中存在记录。

RequiresPermissions:
当前Subject需要拥有某些特定的权限时,才能执行被该注解标注的方法。如果当前Subject不具有这样的权限,则方法不会被执行。

RequiresRoles:
当前Subject必须拥有所有指定的角色时,才能访问被该注解标注的方法。如果当天Subject不同时拥有所有指定角色,则方法不会执行还会抛出AuthorizationException异常。

RequiresUser
当前Subject必须是应用的用户,才能访问或调用被该注解标注的类,实例,方法。