1.pom文件添加shiro与aop依赖
<!-- shiro -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2.目录层次
bean存放实体类
config存放配置类
controller存放控制类
dao存放数据接口
service存放业务类
tools存放公共方法
3.建立实体类
主要实体类分别是用户、角色与权限类
3.1用户类
省略get与set方法
根据情况一些字段可以不要,但是id、username、password与salt是必要的字段属性,salt是密码盐,加密密码必要的属性
这里创建时间与最后一次登录时间使用的是Long,应为我存储的时间是时间戳形式,java获取的时间戳是13位数字超过了无符号int的最大位数
下面的roleList是用户对应多个角色,而用户与角色是多对多的关系,所以role类也应该有类似的属性
3.2角色类
省略get与set
角色类必要的字段也就id与name,可以看情况加上描述与状态等
角色与权限与用户都是多对多关系
3.3权限类
省略get与set方法
和角色类类似,必要的字段也不多,只有id、name与relationUrl就是跳转链接
权限与角色是多对多的关系
3.4数据库表
三个实体类建立之后如果你的数据库中没有相关表,将在你保存的那一刻自动在你的数据库中建立user、role与permission三张表
不过还是建议自己建立,应为自动建立的表没有注释,字段也不是最优字段,下面展示表与建表sql
CREATE TABLE `user` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(20) NOT NULL COMMENT '用户名,登录时使用',
`password` varchar(32) NOT NULL COMMENT '密码',
`email` varchar(64) DEFAULT NULL COMMENT '邮箱',
`phone` int(11) unsigned DEFAULT NULL COMMENT '电话号码',
`nickname` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '昵称,null时使用username',
`salt` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '密码盐',
`ip` varchar(8) DEFAULT NULL COMMENT '最后一次登录ip',
`create_time` bigint(13) unsigned NOT NULL COMMENT '注册时间',
`last_login` bigint(13) unsigned DEFAULT NULL COMMENT '最后一次登录时间',
`is_use` tinyint(1) unsigned NOT NULL DEFAULT '1' COMMENT '状态:0冻结1正常2删除',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户表';
CREATE TABLE `role` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL COMMENT '名称',
`description` varchar(255) DEFAULT NULL COMMENT '描述',
`is_use` tinyint(1) unsigned NOT NULL DEFAULT '1' COMMENT '状态:0弃用1正常',
`create_time` bigint(13) unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
`update_time` bigint(13) unsigned NOT NULL DEFAULT '0' COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='角色表';
CREATE TABLE `permission` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL COMMENT '名称',
`description` varchar(255) DEFAULT NULL COMMENT '描述',
`type` varchar(32) NOT NULL DEFAULT 'menu' COMMENT '类型:menu,botton',
`relation_url` varchar(255) DEFAULT NULL COMMENT '关联链接',
`permission` varchar(32) NOT NULL DEFAULT '*' COMMENT '权限类型:*全部create新增update修改delete删除view查看,多个之间英文逗号分隔',
`super_id` int(10) unsigned DEFAULT NULL COMMENT '父级id',
`create_time` bigint(13) unsigned NOT NULL COMMENT '创建时间',
`update_time` bigint(13) unsigned NOT NULL COMMENT '更新时间',
`is_use` tinyint(1) unsigned NOT NULL DEFAULT '1' COMMENT '状态:0弃用1正常',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='权限表';
4.配置shiro
4.1在config中建立MyRealm.java
这个类作用是做一个链接的权限校验与登录认证,登录认证应该都明白,链接校验就是区分一个用户所拥有的角色是否有访问这个链接的权限
MyRealm类继承AuthorizingRealm
4.1.1链接校验
链接校验方法用了两层for循环将该用户角色下所有的权限遍历出来一一校对是否有访问权限
4.1.2登录认证
方法内有部分注释也就不全说了,主要要说的是new SimpleAuthentication中的四个参数
user指user类
user.getPassword()指用户存在数据库中的密码
ByteSource.Util.bytes(user.getSalt())指用户密码盐
getName()就是realm的name
4.2同在config包下建立ShiroConfig.java类
4.2.1过滤器方法shiroFilter
注释已经说得很清楚了,这里就强调一点
就是是这个方法是顺序执行的/**一定要放在后面
4.2.2其余方法
需要注意的就是第一个方法的散列算法与散列算法次数,需要与注册方法相匹配,不然登录会出问题
5.注册
注册与登录将会以一个流程的形式展示代码,而不是直接把一个类一个接口的代码直接粘贴出来
5.1前端注册页面
在src/main/resources/templates中建立login.html
这里把注册和登录放在一个界面中
前台页面效果
很简单的一个界面具体怎么写就不去讨论了
5.2在controller包中建立UserController,然后建立注册控制方法regist
5.3在Service包中建立UserService类,编写控制器类需要用到的注册方法regist()
上面两个方法基本理解起来应该不难,只是多了两个工具类的使用
一个是EncryptionUtil与Complex
Complex工具类的isNumber方法就不展示了,这只是个简单的判断字符串是否能转换成Long或其他数字的方法
而EncryptionUtil方法也稍微放后面
5.4在dao包中建立UserRepository仓库接口
这个接口你不必去实现它,它会自动通过你提供的东西去查询
比如findByUsername会自动将你提供的string拿去在数据库中匹配username字段
5.5在tools包中建立Complex.java与EncryptionUtil.java两个工具类
Complex是复杂工具,存储的方法都为静态,可以直接调用与各种类与方法中,里面的方法没有什么关联性
EncryptionUtil是专门做加密工作的工具类
这是将传来的原始密码字符串进行加密的方法
salt是系统生成的密码盐,为32字符的字符串
password则是用md5散列算法将原始密码+密码盐进行两次加密,这里要与ShiroConfig类中的hashedCredentialsMatcher()方法里面的说明匹配
返回密码盐与加密密码的map
到这里整个注册流程就算完成了
6.登录
6.1前端代码
同样是在login.html中
这里th:src="@{/validateCode}"是thymeleaf的语法,就是请求后端带有"/validateCode"注释的方法,获取验证码,这里先不介绍了
前台展示
5.2控制类
同样是在UserController中创建登录方法login()
不过这里的login只处理失败的情况,成功的情况在ShiroConfig中处理
具体的方法解释注释也说的比较明白了
@resource下面的两行可以忽略,那个是验证码方法使用的
至于Service与Repository就不再重复展示了,登录需要用到前面提到的UserService.findByNameOrPhone()方法与注册重叠了