2.springboot整合Shrio 02

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>

有错误的话欢迎指正!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值