1.pom.xml
和之前一样 只是多加了阿里连接池
com.alibaba
druid
<!--thymeleaf-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--shiro支持-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<!--持久层框架mybatis和mysql驱动8.0.9-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--阿里连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.14</version>
</dependency>
<!--插件简化代码-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
2.application.properties
pring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=1234
spring.datasource.url=jdbc:mysql://localhost:3306/shiro?characterEncoding=utf8&allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=Asia/Shanghai
#缓存关闭
spring.thymeleaf.cache=false
#mapper包扫描
mybatis.mapper-locations=classpath:mapper/*.xml
#实体类别名
mybatis.type-aliases-package=com.shiro.pojo
#驼峰命名开启
mybatis.configuration.map-underscore-to-camel-case=true
#session
server.servlet.session.timeout=5
spring.mvc.hiddenmethod.filter.enabled=true
spring.profiles.active=pro
application-pro.properties文件专门放阿里连接池配置
#连接池配置阿里巴巴的
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
3.sql
#创建数据库 shiro
DROP DATABASE IF EXISTS shiro;
CREATE DATABASE IF NOT EXISTS shiro;
#切换数据库
USE shiro;
#删
DROP TABLE IF EXISTS USER;
DROP TABLE IF EXISTS role;
DROP TABLE IF EXISTS permission;
DROP TABLE IF EXISTS user_role;
DROP TABLE IF EXISTS role_permission;
#创建
CREATE TABLE USER (
id BIGINT AUTO_INCREMENT,
NAME VARCHAR(100),
PASSWORD VARCHAR(100),
salt VARCHAR(100),
CONSTRAINT pk_users PRIMARY KEY(id)
) CHARSET=utf8 ENGINE=INNODB;
CREATE TABLE role (
id BIGINT AUTO_INCREMENT,
NAME VARCHAR(100),
desc_ VARCHAR(100),
CONSTRAINT pk_roles PRIMARY KEY(id)
) CHARSET=utf8 ENGINE=INNODB;
CREATE TABLE permission (
id BIGINT AUTO_INCREMENT,
NAME VARCHAR(100),
desc_ VARCHAR(100),
url VARCHAR(100),
CONSTRAINT pk_permissions PRIMARY KEY(id)
) CHARSET=utf8 ENGINE=INNODB;
CREATE TABLE user_role (
id BIGINT AUTO_INCREMENT,
uid BIGINT,
rid BIGINT,
CONSTRAINT pk_users_roles PRIMARY KEY(id)
) CHARSET=utf8 ENGINE=INNODB;
CREATE TABLE role_permission (
id BIGINT AUTO_INCREMENT,
rid BIGINT,
pid BIGINT,
CONSTRAINT pk_roles_permissions PRIMARY KEY(id)
) CHARSET=utf8 ENGINE=INNODB;
#插入
INSERT INTO `permission` VALUES (1,'addProduct','增加产品','/addProduct');
INSERT INTO `permission` VALUES (2,'deleteProduct','删除产品','/deleteProduct');
INSERT INTO `permission` VALUES (3,'editeProduct','编辑产品','/editeProduct');
INSERT INTO `permission` VALUES (4,'updateProduct','修改产品','/updateProduct');
INSERT INTO `permission` VALUES (5,'listProduct','查看产品','/listProduct');
INSERT INTO `permission` VALUES (6,'addOrder','增加订单','/addOrder');
INSERT INTO `permission` VALUES (7,'deleteOrder','删除订单','/deleteOrder');
INSERT INTO `permission` VALUES (8,'editeOrder','编辑订单','/editeOrder');
INSERT INTO `permission` VALUES (9,'updateOrder','修改订单','/updateOrder');
INSERT INTO `permission` VALUES (10,'listOrder','查看订单','/listOrder');
INSERT INTO `role` VALUES (1,'admin','超级管理员');
INSERT INTO `role` VALUES (2,'productManager','产品管理员');
INSERT INTO `role` VALUES (3,'orderManager','订单管理员');
INSERT INTO `role_permission` VALUES (1,1,1);
INSERT INTO `role_permission` VALUES (2,1,2);
INSERT INTO `role_permission` VALUES (3,1,3);
INSERT INTO `role_permission` VALUES (4,1,4);
INSERT INTO `role_permission` VALUES (5,1,5);
INSERT INTO `role_permission` VALUES (6,1,6);
INSERT INTO `role_permission` VALUES (7,1,7);
INSERT INTO `role_permission` VALUES (8,1,8);
INSERT INTO `role_permission` VALUES (9,1,9);
INSERT INTO `role_permission` VALUES (10,1,10);
INSERT INTO `role_permission` VALUES (11,2,1);
INSERT INTO `role_permission` VALUES (12,2,2);
INSERT INTO `role_permission` VALUES (13,2,3);
INSERT INTO `role_permission` VALUES (14,2,4);
INSERT INTO `role_permission` VALUES (15,2,5);
INSERT INTO `role_permission` VALUES (50,3,10);
INSERT INTO `role_permission` VALUES (51,3,9);
INSERT INTO `role_permission` VALUES (52,3,8);
INSERT INTO `role_permission` VALUES (53,3,7);
INSERT INTO `role_permission` VALUES (54,3,6);
INSERT INTO `role_permission` VALUES (55,3,1);
INSERT INTO `role_permission` VALUES (56,5,11);
INSERT INTO `user` VALUES (1,'zhang3','a7d59dfc5332749cb801f86a24f5f590','e5ykFiNwShfCXvBRPr3wXg==');
INSERT INTO `user` VALUES (2,'li4','43e28304197b9216e45ab1ce8dac831b','jPz19y7arvYIGhuUjsb6sQ==');
INSERT INTO `user_role` VALUES (43,2,2);
INSERT INTO `user_role` VALUES (45,1,1);
#getPassword 方法: 查密码
SELECT PASSWORD FROM USER WHERE NAME ='li4'
# listRoles 方法: 根据用户名查询此用户有哪些角色,这是3张表的关联
SELECT r.name FROM USER u
LEFT JOIN user_role ur ON u.id = ur.uid
LEFT JOIN Role r ON r.id = ur.rid
WHERE u.name = 'zhang3';
#listPermissions 方法:根据用户名查询此用户有哪些权限,这是5张表的关联
SELECT p.name FROM USER u
LEFT JOIN user_role ru ON u.id = ru.uid
LEFT JOIN role r ON r.id = ru.rid
LEFT JOIN role_permission rp ON r.id = rp.rid
LEFT JOIN permission p ON p.id = rp.pid
WHERE u.name ='li4'
4.通过idea连接数据库快速创建pojo类,导包名修改一下即可
5.UserDao 和UserService(省略)
@Repository
@Mapper
public interface UserDao {
//根据用户名查密码
@Select ("SELECT PASSWORD FROM USER WHERE NAME =#{name}")
String getPwdByName(String name);
//三表查询,根据用户名查询角色
List<String> listRoles(String name);
//根据用户名查询 权限 五表查询
List<String> listPermissions(String name);
}
@Service
public class UserServiceImpl implements UserService {
@Autowired
UserDao userDao;
@Override
public String getPwdByName(String name) {
return userDao.getPwdByName (name);
}
@Override
public List<String> listRoles(String name) {
return userDao.listRoles (name);
}
@Override
public List<String> listPermissions(String name) {
return userDao.listPermissions (name);
}
}
6.接下来是修改认证逻辑:
/*授权和认证逻*/
public class CustomRealm extends AuthorizingRealm {
@Autowired
UserService userService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println ("执行授权逻辑");
SimpleAuthorizationInfo simpleInfo = new SimpleAuthorizationInfo ( );
//获取登录用户名
String name = (String) principalCollection.getPrimaryPrincipal ( );
//之后在数据库查询他是什么角色 什么权限一一添加他们
System.out.println ("查询角色和权限:" + name);
List<String> listRoles = userService.listRoles (name);
// simpleInfo.addRoles (listRoles);直接添加多个角色或者forench添加
for (String role : listRoles) {
simpleInfo.addRole (role);
}
//添加角色下的权限 比如crud
List<String> listPermissions = userService.listPermissions (name);
simpleInfo.addStringPermissions (listPermissions);
//设置好权限返回
return simpleInfo;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//加这一步的目的是在Post请求的时候会先进认证,然后在到请求
if (null == authenticationToken.getPrincipal ( )) {
return null;
}
System.out.println ("执行认证逻辑");
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
//获取用户登陆的名
String name = token.getUsername ( );
String pwd = userService.getPwdByName (name);
if (null == pwd) {
//用户名不存在
return null;//抛出一个空的对象 抛出异常UnknowAccountException
}
//这里验证authenticationToken和simpleAuthenticationInfo的信息
return new SimpleAuthenticationInfo (name, pwd, getName ( ));
}
}
7.Shiro配置:
/*常用的过滤器
* anon:无认证
* authc:必须认证 登陆即可
* user: 使用记住我可以直接访问
* perms: 必须有资源权限 比如crud
* roles: 必须有角色权限
* */
@Configuration
public class ShiroConfig {
/**
* 创建自定义配置的Realm
*/
@Bean
CustomRealm myRealm() {
return new CustomRealm ( );
}
/**
* 创建DefaultWebSecurityManager管理器,使它管理自定义的Realm
*/
@Bean
DefaultWebSecurityManager securityManager() {
DefaultWebSecurityManager manager = new DefaultWebSecurityManager ( );
manager.setRealm (myRealm ( ));
return manager;
}
/**
*创建shiroFilterFactoryBean
* 关联一个securityManager ( )管理器
*/
@Bean
ShiroFilterFactoryBean shiroFilterFactoryBean() {
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean ( );
bean.setSecurityManager (securityManager ( ));
//登陆页
bean.setLoginUrl ("/login");
//登陆成功后界面
bean.setSuccessUrl ("/index");
//未授权跳转到
bean.setUnauthorizedUrl ("/tip");
Map<String, String> map = new LinkedHashMap<> ( );
//anon是把限制权限改为无限制
//map.put ("/index", "anon");
//authc 登陆后可以访问
// map.put ("/**", "authc");
map.put ("/add", "authc");
//权限必须有addProduct才可以访问
map.put ("/update","perms[addProduct]");
//角色是admin 才可以访问超级管理员界面
map.put ("/admin","roles[admin]");
bean.setFilterChainDefinitionMap (map);
return bean;
}
}
8.controller
@Controller
public class LoginController {
//表单提交,处理后返回首页
@PostMapping("/tologin")
String tologin(String name, String password, Model model) {
//处理逻辑
/**使用Shiro编写认证操作*/
//1.获取Subject
Subject subject = SecurityUtils.getSubject ( );
//2.封装用户数据
UsernamePasswordToken token = new UsernamePasswordToken (name, password);
//执行登陆方法
try {
subject.login (token);
//登陆信息会交给Realm去执行认证逻辑,比如去数据库对比用户,密码
//然后会设置角色,权限
} catch (UnknownAccountException e) {
model.addAttribute ("msg", "用户名不存在");
return "/login";
} catch (IncorrectCredentialsException e) {
model.addAttribute ("msg", "密码错误");
return "/login";
}
//这里的请求不能返回"/index"这是返回index.html了 没有经过mvc拦截到
// 必须使用"redirect:/index" 或者"forward:/index"
//catch块可以跳转是因为我的页面就叫login.html 请求也是/login
return "redirect:/index";
}
@RequestMapping("/tip")
@ResponseBody
String tip(){
return "抱歉,您没有权限访问该页面!";
}
}
@Controller
public class UserController {
@GetMapping("/login")
String login() {
return "login";
}
@RequestMapping("/index")
String test() {
return "test";
}
@GetMapping("/add")
String add() {
return "add";
}
@GetMapping("/update")
String update() {
return "update";
}
@ResponseBody
@GetMapping("/admin")
String admin() {
return "欢迎您超级管理者!";
}
}
路径是这样的先请求/index 返回到首页展示三链接(/add,/update,/admin)
点击后后被拦截到登陆页/login 账号密码post提交后到/tologin 数据库查询无误后返回首页,有误返回登陆页
这时候可以访问三链接 有权限放行 没有则跳转到提示信息/tip
9.html
add.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户添加页面</title>
</head>
<body>
用户添加
</body>
</html>
update.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户更改的页面</title>
</head>
<body>
用户更改
</body>
</html>
test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户的测试页面</title>
</head>
<body>
<h2 th:text="${name}"></h2>
<hr/>
<p> 进入用户添加功能:<a href="/add">用户添加,登陆就可以操作</a></p>
<p>进入用户更新功能:<a href="/update">用户更新,拥有addProduct权限可以操作</a></p>
<p><a href="/admin">超级管理admin角色界面</a></p>
</body>
</html>
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登陆页面</title>
</head>
<body>
<h3 th:text="${msg}" style="color: red"></h3>
<form method="post" action="/tologin">
用户名:<input type="text" name="name"/> <br/>
密码:<input type="password" name="password"><br/>
<input type="submit" value="登陆">
</form>
</body>
</html>
10.测试
有两个用户 zhang3为admin 角色 有许多权限可以查sql li4是个经理 没有admin权限
10.1.乱输一个
10.2.登陆张三,然后访问三界面:全部可以
10.3.换成li4登陆.在访问:
/admin返回了302状态 然后发给了/tip
**补上mapper.xml:**可以通过选中dao名按住ALT+enter快速创建映射,再选择方法名创建…
<?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.shiro.dao.UserDao">
<select id="listRoles" resultType="java.lang.String">
SELECT r.name FROM USER u
LEFT JOIN user_role ur ON u.id = ur.uid
LEFT JOIN Role r ON r.id = ur.rid
WHERE u.name =#{name}
</select>
<select id="listPermissions" resultType="java.lang.String">
SELECT p.name FROM USER u
LEFT JOIN user_role ru ON u.id = ru.uid
LEFT JOIN role r ON r.id = ru.rid
LEFT JOIN role_permission rp ON r.id = rp.rid
LEFT JOIN permission p ON p.id = rp.pid
WHERE u.name =#{name}
</select>
</mapper>
有错误的话欢迎指正!