目录
- 1、开发环境:
- 2.数据库设计
- 3.目录结构
- 3.1pom
- 3.2application.yml
- 3.3实体类
- 3.4 dao
- 3.5mapper
- 3.6 ShiroConfig
- 3.7 MyRealm
- 3.8 controller
- 3.9 启动类
- 4.templates页面
- 4.1 error.html
- 4.2 index.html
- 4.3 login.html
- 4.4 unauth.html
- 5.TestMD5加密
- 6.测试
- 7.附数据库语句,有数据
1、开发环境:
1、mysql - 5.7
2、navicat(mysql客户端管理工具)
3、idea 2017.2
4、jdk8
5、tomcat 8.5
6、springboot2.0.3
7、mybatis 3
8、shiro1.4
9、maven3.3.9
2.数据库设计
3.目录结构
3.1pom
<?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.wo</groupId>
<artifactId>shiro_springboot</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!--shiro的包-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>
3.2application.yml
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
username: root
password: 123456
url: jdbc:mysql://localhost:3306/qf?useUnicode=true&characterEncoding=utf8&useSSL=false
mybatis:
mapper-locations: classpath:mapper/*Mapper.xml
3.3实体类
1.TbSysUser
@Data
public class TbSysUser {
private Integer userid;
private String loginName;
private String password;
}
2.TbSysPermissions
@Data
public class TbSysPermissions {
private Integer permissionId;
private String perName;
}
3.4 dao
1.TbUserDao
@Mapper
public interface TbUserDao {
TbSysUser login(@Param("loginName") String loginName);
}
2.TbSysPermissionDao
@Mapper
public interface TbSysPermissionDao {
List<TbSysPermissions> findPermissonByLoginName(@Param("loginName") String loginName);
}
3.5mapper
1.TbUserMapper.xml
<?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.wo.dao.TbUserDao">
<resultMap id="BaseResult" type="com.wo.pojo.TbSysUser">
<id property="userid" column="userid"></id>
<result property="loginName" column="login_name"></result>
<result property="password" column="password"></result>
</resultMap>
<select id="login" resultMap="BaseResult">
select * from tb_sys_user where login_name = #{loginName}
</select>
</mapper>
2.TbPermissionMapper.xml
<?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.wo.dao.TbSysPermissionDao">
<resultMap id="BaseResult" type="com.wo.pojo.TbSysPermissions">
<id property="permissionId" column="permission_id"></id>
<result property="perName" column="per_name"></result>
</resultMap>
<select id="findPermissonByLoginName" resultMap="BaseResult">
SELECT sp.per_name from tb_sys_user su,tb_sys_role sr,tb_sys_permission sp, tb_user_role ur,tb_role_permission rp
where su.userid=ur.user_id
and ur.role_id = sr.role_id
and sr.role_id = rp.role_id
and rp.permission_id = sp.permission_id
and su.login_name=#{loginName};
</select>
</mapper>
3.6 ShiroConfig
package com.wo.config;
@Configuration
public class ShiroConfig {
//1.获取到我们的myrealm
@Bean(name = "myRealm")
public MyRealm myRealm(@Qualifier("hashedCredentialsMatcher")HashedCredentialsMatcher matcher){
MyRealm myRealm = new MyRealm();
myRealm.setAuthorizationCachingEnabled(false);
myRealm.setCredentialsMatcher(matcher);
return myRealm;
}
//2.声明securityManager
@Bean(name = "defaultWebSecurityManager")
public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("myRealm") MyRealm myRealm){
//shiro核心
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
//在核心中设置我们自定义的realm
defaultWebSecurityManager.setRealm(myRealm);
return defaultWebSecurityManager;
}
//3.工厂
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager")DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
//权限
//声明没有权限的情况下走的接口名称
shiroFilterFactoryBean.setUnauthorizedUrl("/unauth");
// //告诉shiro有用什么权限可以访问什么接口
//如果不加注解不加map,默认没有权限控制
// Map map = new HashMap<>();
// map.put("/findAll","perms[user_findAll]");
// map.put("/deleteById","perms[user_delete]");
// //将访问接口的权限放置到shiroFileter中
// shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return shiroFilterFactoryBean;
}
//使用aop注解模式来使用权限
//使用aop扫描包含shiro注解的类
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
return defaultAdvisorAutoProxyCreator;
}
//将WebSecurityManager 交给spring aop来进行管理
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("defaultWebSecurityManager")DefaultWebSecurityManager defaultWebSecurityManager){
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(defaultWebSecurityManager);
return authorizationAttributeSourceAdvisor;
}
/**
* 密码校验规则HashedCredentialsMatcher
* 这个类是为了对密码进行编码的 ,
* 防止密码在数据库里明码保存 , 当然在登陆认证的时候 ,
* 这个类也负责对form里输入的密码进行编码
* 处理认证匹配处理器:如果自定义需要实现继承HashedCredentialsMatcher
*/
@Bean("hashedCredentialsMatcher")
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
//指定加密方式为MD5
credentialsMatcher.setHashAlgorithmName("MD5");
//加密次数
credentialsMatcher.setHashIterations(1);
credentialsMatcher.setStoredCredentialsHexEncoded(true);
return credentialsMatcher;
}
}
3.7 MyRealm
@Component
public class MyRealm extends AuthorizingRealm {
@Autowired
TbUserDao tbUserDao;
@Autowired
TbSysPermissionDao tbSysPermissionDao;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//获取到前端传输用户名
String username = (String) principalCollection.getPrimaryPrincipal();
//使用用户名查询该用户的权限
List<TbSysPermissions> permissonByLoginName = tbSysPermissionDao.findPermissonByLoginName(username);
//声明set进行去重
HashSet<String> set=new HashSet<>();
for (TbSysPermissions tb:permissonByLoginName) {
set.add(tb.getPerName());
}
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
simpleAuthorizationInfo.setStringPermissions(set);
return simpleAuthorizationInfo;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//获得到用户名
String username = (String) authenticationToken.getPrincipal();
//使用用户名查询密码
TbSysUser user = tbUserDao.login(username);
//不使用加盐加密
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(username, user.getPassword(), getName());
//使用加盐加密
//SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(username, user.getPassword(),ByteSource.Util.bytes("wang"), getName());
return simpleAuthenticationInfo;
}
}
3.8 controller
1.UserController
@Controller
public class UserController {
@RequestMapping("/tologin")
public String tologin(){
return "login";
}
@RequestMapping("/login")
public String login(TbSysUser tbSysUser){
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(tbSysUser.getLoginName(), tbSysUser.getPassword());
try {
subject.login(token);
}catch (IncorrectCredentialsException ini){
System.out.println(ini.getMessage());
}
if (subject.isAuthenticated()){
return "redirect:findAll";
}else{
return "login";
}
}
@RequestMapping("/logout")
public String logout(){
Subject subject = SecurityUtils.getSubject();
subject.logout();
return "login";
}
@RequiresPermissions(value = {"user_findAll"})
@RequestMapping("/findAll")
public String findALL(){
return "index";
}
@RequiresPermissions(value = {"user_deletesss"})
@RequestMapping("/deleteById")
public String deleteById(){
return "index";
}
@RequestMapping("/unauth")
public String unauth(){
return "unauth";
}
}
2.PermissionExcepitonController
//控制器增强 异常捕获类
@ControllerAdvice
public class PermissionExcepitonController {
//告诉控制器 捕捉什么类型的异常 以及对异常进行处理
@ExceptionHandler(value = AuthorizationException.class)
public String excepiton(){
return "unauth";
}
@ExceptionHandler(value = ArithmeticException.class)
public String urithmeticException(){
return "error";
}
}
3.9 启动类
@SpringBootApplication
public class ShiroSpringBootApplication {
public static void main(String[] args) {
SpringApplication.run(ShiroSpringBootApplication.class);
}
}
4.templates页面
4.1 error.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>您当前的操作有误,请稍后再试</h1>
</body>
</html>
4.2 index.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>用户登录成功</h1>
<a href="/logout">退出登录</a>
</body>
</html>
4.3 login.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/login" method="post">
用户名:<input type="text" name="loginName"><br>
密码:<input type="password" name="password"><br>
<input type="submit" value="提交">
</form>
</body>
</html>
4.4 unauth.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>您没有权限,请联系管理员</h1>
</body>
</html>
5.TestMD5加密
@RunWith(SpringRunner.class)
@SpringBootTest
public class TestMD5 {
@Test
public void getMD5PassWord(){
String hashAlgorithName = "MD5";//加密算法
String password = "123";//登陆时的密码
int hashIterations =1;//加密次数
ByteSource credentialsSalt = ByteSource.Util.bytes("admin");//使用登录名做为salt
SimpleHash simpleHash = new SimpleHash(hashAlgorithName, password, credentialsSalt, hashIterations);
System.out.println(simpleHash);
}
}
6.测试
1.登录
2.登录admn账户,该账户有findAll权限,但是没有delete权限
7.附数据库语句,有数据
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for `tb_role_permission`
-- ----------------------------
DROP TABLE IF EXISTS `tb_role_permission`;
CREATE TABLE `tb_role_permission` (
`role_id` int(11) NOT NULL,
`permission_id` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of tb_role_permission
-- ----------------------------
INSERT INTO `tb_role_permission` VALUES ('1', '1');
INSERT INTO `tb_role_permission` VALUES ('2', '1');
INSERT INTO `tb_role_permission` VALUES ('3', '1');
INSERT INTO `tb_role_permission` VALUES ('3', '2');
INSERT INTO `tb_role_permission` VALUES ('3', '3');
INSERT INTO `tb_role_permission` VALUES ('2', '2');
-- ----------------------------
-- Table structure for `tb_sys_permission`
-- ----------------------------
DROP TABLE IF EXISTS `tb_sys_permission`;
CREATE TABLE `tb_sys_permission` (
`permission_id` int(11) NOT NULL AUTO_INCREMENT,
`per_name` varchar(255) DEFAULT NULL,
`menu_name` varchar(255) DEFAULT NULL,
`menu_type` varchar(255) DEFAULT NULL,
`menu_url` varchar(255) DEFAULT NULL,
`menu_code` varchar(255) DEFAULT NULL,
`parent_code` varchar(255) DEFAULT NULL,
`per_desc` varchar(255) DEFAULT NULL,
`if_vilid` tinyint(4) DEFAULT NULL,
PRIMARY KEY (`permission_id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of tb_sys_permission
-- ----------------------------
INSERT INTO `tb_sys_permission` VALUES ('1', 'user_findAll', null, null, null, null, null, null, null);
INSERT INTO `tb_sys_permission` VALUES ('2', 'user_delete', null, null, null, null, null, null, null);
INSERT INTO `tb_sys_permission` VALUES ('3', 'user_update', null, null, null, null, null, null, null);
-- ----------------------------
-- Table structure for `tb_sys_role`
-- ----------------------------
DROP TABLE IF EXISTS `tb_sys_role`;
CREATE TABLE `tb_sys_role` (
`role_id` int(11) NOT NULL AUTO_INCREMENT,
`role_name` varchar(255) DEFAULT NULL,
`role_deso` varchar(255) DEFAULT NULL,
`if_vilid` tinyint(4) DEFAULT NULL,
PRIMARY KEY (`role_id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of tb_sys_role
-- ----------------------------
INSERT INTO `tb_sys_role` VALUES ('1', '普通会员', '查询', null);
INSERT INTO `tb_sys_role` VALUES ('2', '管理员', '查询和删除', null);
INSERT INTO `tb_sys_role` VALUES ('3', '超级管理员', '查询删除新增或更新', null);
-- ----------------------------
-- Table structure for `tb_sys_user`
-- ----------------------------
DROP TABLE IF EXISTS `tb_sys_user`;
CREATE TABLE `tb_sys_user` (
`userid` int(11) NOT NULL AUTO_INCREMENT,
`login_name` varchar(255) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
`state` tinyint(4) DEFAULT NULL,
`create_time` datetime DEFAULT NULL,
`realname` varchar(255) DEFAULT NULL,
PRIMARY KEY (`userid`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of tb_sys_user
-- ----------------------------
INSERT INTO `tb_sys_user` VALUES ('1', 'normal111', '202cb962ac59075b964b07152d234b70', '1', '2019-07-05 11:17:03', 'zhangsan');
INSERT INTO `tb_sys_user` VALUES ('2', 'normal222', '202cb962ac59075b964b07152d234b70', '1', '2020-09-18 19:57:43', 'lisi');
INSERT INTO `tb_sys_user` VALUES ('3', 'admin', '202cb962ac59075b964b07152d234b70', '1', '2020-09-17 19:58:34', 'wangwu');
INSERT INTO `tb_sys_user` VALUES ('4', 'root', '202cb962ac59075b964b07152d234b70', '1', '2020-09-24 19:58:50', 'zhangfei');
-- ----------------------------
-- Table structure for `tb_user_role`
-- ----------------------------
DROP TABLE IF EXISTS `tb_user_role`;
CREATE TABLE `tb_user_role` (
`user_id` int(11) NOT NULL AUTO_INCREMENT,
`role_id` int(11) DEFAULT NULL,
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of tb_user_role
-- ----------------------------
INSERT INTO `tb_user_role` VALUES ('1', '1');
INSERT INTO `tb_user_role` VALUES ('2', '1');
INSERT INTO `tb_user_role` VALUES ('3', '2');
INSERT INTO `tb_user_role` VALUES ('4', '3');