欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

【原】无脑操作:IDEA + maven + Shiro + SpringBoot + JPA + Thymeleaf实现基础认证权限

程序员文章站 2022-04-26 17:59:40
上一篇《【原】无脑操作:IDEA + maven + Shiro + SpringBoot + JPA + Thymeleaf实现基础认证权限》介绍了实现Shiro的基础认证。本篇谈谈实现Shiro的基础授权。 需求: ① 某系统有公共模块、领导模块、管理员模块三个业务模块,均需要登录系统后才可以访 ......

上一篇《【原】无脑操作:idea + maven + shiro + springboot + jpa + thymeleaf实现基础认证权限》介绍了实现shiro的基础认证。本篇谈谈实现shiro的基础授权。

需求:

① 某系统有公共模块、领导模块、管理员模块三个业务模块,均需要登录系统后才可以访问。

② admin、leader、employee三个人职位分别是管理员、领导、员工,均可登录系统。

③ 不同职位的人登录系统后,能看到的功能模块不同。管理员可以访问全部三个模块。领导可以访问除去管理员模块外的两个模块。员工只能访问公共模块。

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------

分析:

典型的运用授权权限的需求,继续考虑使用shiro。

问题1、认证和授权怎么理解呢?

答:一点粗浅理解,比如通过了美国的签证能进入美国了,这就是获得了认证。

但是进入美国了,也只能去有授权的地方玩玩,五角大楼能进么?没有授权是不给进的。

所以,授权是在认证获得后进一步的安全管理。

问题2、需求在描述什么场景?

答:需求中包含了基于角色的权限访问控制rbac(role-based access control)的设计思路。

简单来说,单个人对某某资源可操作。

【原】无脑操作:IDEA + maven + Shiro + SpringBoot + JPA + Thymeleaf实现基础认证权限

进一步考虑,如果是多个人对某某资源可操作呢?需要重复的这样设置么?运用归纳思想,把这样的多个人归为一类,形成了角色的概念。即这一角色的多个人对某某资源可操作。

rbac认为权限授权实际上是who、what、how的问题。在rbac模型中,who、what、how构成了访问权限三元组,也就是“who对what(which)进行how的操作”。【原】无脑操作:IDEA + maven + Shiro + SpringBoot + JPA + Thymeleaf实现基础认证权限

问题3、针对本需求的rbac设计是怎么样的?

答:简化设计为:用户和角色为多对一关系、角色和资源为多对多关系

【原】无脑操作:IDEA + maven + Shiro + SpringBoot + JPA + Thymeleaf实现基础认证权限

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 0、数据库建表init.sql

 1 -- 初始化
 2 drop table sys_user;
 3 drop table sys_role;
 4 drop table sys_resource;
 5 drop table sys_role_resource;
 6 
 7 -- 用户信息表
 8 create table sys_user
 9 (
10     userid int auto_increment primary key comment '用户编号',
11     username varchar(10) not null comment '用户名称',
12     `password` varchar(10) not null comment '用户密码',
13     roleid int not null comment '角色编号'
14 );
15 
16 insert into sys_user values(null, 'admin', '123', 1), (null, 'leader', '456', 2), (null, 'employee', '789', 3);
17 
18 select * from sys_user;
19 
20 -- 角色信息表
21 create table sys_role
22 (
23     roleid int auto_increment primary key comment '角色编号',
24     rolename varchar(10) not null comment '角色名称'
25 );
26 
27 insert into sys_role values(null, '管理员'), (null, '领导'), (null, '员工');
28 
29 select * from sys_role;
30 
31 -- 资源信息表
32 create table sys_resource
33 (
34     resourceid int auto_increment primary key comment '资源编号',
35     resourcename varchar(10) not null comment '资源名称',
36     resourceurl varchar(50) not null comment '资源url'
37 );
38 
39 insert into sys_resource values
40 (null, '公共模块', 'publicmodule'),
41 (null, '领导模块', 'leadermodule'),
42 (null, '管理员模块', 'adminmodule');
43 
44 select * from sys_resource;
45 
46 -- 角色资源关联表
47 create table sys_role_resource
48 (
49     id int auto_increment primary key comment '关联编号',
50     roleid int not null comment '角色编号',
51     resourceid int not null comment '资源编号'
52 );
53 
54 insert into sys_role_resource values
55 (null, 1, 1), (null, 1, 2), (null, 1, 3),
56 (null, 2, 1), (null, 2, 2),
57 (null, 3, 1);
58 
59 select * from sys_role_resource;
60 
61 -- 获取用户能访问的资源url
62 select u.userid, rs.resourceurl
63 from sys_role_resource as rr
64 inner join sys_resource as rs on rr.resourceid = rs.resourceid
65 inner join sys_role as r on rr.roleid = r.roleid
66 inner join sys_user as u on u.roleid = r.roleid
67 where u.userid = 1;

 

1、编写项目对象模型文件pom.xml

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <project xmlns="http://maven.apache.org/pom/4.0.0"
 3          xmlns:xsi="http://www.w3.org/2001/xmlschema-instance"
 4          xsi:schemalocation="http://maven.apache.org/pom/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 5     <modelversion>4.0.0</modelversion>
 6 
 7     <groupid>cn.temptation</groupid>
 8     <artifactid>studyshiro</artifactid>
 9     <version>1.0-snapshot</version>
10 
11     <parent>
12         <groupid>org.springframework.boot</groupid>
13         <artifactid>spring-boot-starter-parent</artifactid>
14         <version>2.0.4.release</version>
15     </parent>
16 
17     <dependencies>
18         <!-- web -->
19         <dependency>
20             <groupid>org.springframework.boot</groupid>
21             <artifactid>spring-boot-starter-web</artifactid>
22         </dependency>
23         <!-- thymeleaf -->
24         <dependency>
25             <groupid>org.springframework.boot</groupid>
26             <artifactid>spring-boot-starter-thymeleaf</artifactid>
27         </dependency>
28         <!-- spring data jpa -->
29         <dependency>
30             <groupid>org.springframework.boot</groupid>
31             <artifactid>spring-boot-starter-data-jpa</artifactid>
32         </dependency>
33         <!-- mariadb -->
34         <dependency>
35             <groupid>org.mariadb.jdbc</groupid>
36             <artifactid>mariadb-java-client</artifactid>
37             <version>2.2.5</version>
38         </dependency>
39         <!-- shiro -->
40         <dependency>
41             <groupid>org.apache.shiro</groupid>
42             <artifactid>shiro-spring</artifactid>
43             <version>1.4.0</version>
44         </dependency>
45         <!-- thymeleaf-extras-shiro -->
46         <dependency>
47             <groupid>com.github.theborakompanioni</groupid>
48             <artifactid>thymeleaf-extras-shiro</artifactid>
49             <version>2.0.0</version>
50         </dependency>
51         <!-- 热启动 -->
52         <dependency>
53             <groupid>org.springframework.boot</groupid>
54             <artifactid>spring-boot-devtools</artifactid>
55             <optional>true</optional>
56         </dependency>
57     </dependencies>
58 </project>

 

2、编写项目配置文件application.properties

 1 # 数据库访问配置
 2 # 对应mariadb驱动
 3 spring.datasource.driverclassname=org.mariadb.jdbc.driver
 4 
 5 # 数据源配置
 6 spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test
 7 spring.datasource.username=root
 8 spring.datasource.password=sa
 9 
10 # 配置springboot默认支持的hikari数据库连接池
11 spring.datasource.type=com.zaxxer.hikari.hikaridatasource
12 spring.datasource.hikari.minimum-idle=5
13 spring.datasource.hikari.maximum-pool-size=15
14 spring.datasource.hikari.auto-commit=true
15 spring.datasource.hikari.idle-timeout=30000
16 spring.datasource.hikari.pool-name=datebookhikaricp
17 spring.datasource.hikari.max-lifetime=1800000
18 spring.datasource.hikari.connection-timeout=30000
19 spring.datasource.hikari.connection-test-query=select 1
20 
21 # spring data jpa配置
22 spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.mysql5innodbdialect
23 spring.jpa.properties.hibernate.hbm2ddl.auto=update
24 spring.jpa.show-sql=true
25 spring.jpa.properties.hibernate.format_sql=true
26 
27 # 格式化输出的json字符串
28 spring.jackson.serialization.indent_output=true
29 
30 # 设置控制台彩色打印
31 spring.output.ansi.enabled=always

 

3、编写项目启动类application.java

 1 package cn.temptation;
 2 
 3 import org.springframework.boot.springapplication;
 4 import org.springframework.boot.autoconfigure.springbootapplication;
 5 
 6 @springbootapplication
 7 public class application {
 8     public static void main(string[] args) {
 9         // springboot项目启动
10         springapplication.run(application.class, args);
11     }
12 }

 

4、编写全局异常处理类globalexceptionhandler.java

 1 package cn.temptation.util;
 2 
 3 import org.springframework.web.bind.annotation.controlleradvice;
 4 import org.springframework.web.bind.annotation.exceptionhandler;
 5 
 6 /**
 7  * 全局异常处理类
 8  */
 9 @controlleradvice
10 public class globalexceptionhandler {
11     @exceptionhandler(value = exception.class)
12     public string errorhandler(exception exception) {
13         return "redirect:/error/500";
14     }
15 }

 

5、编写错误页配置类errorpageconfig.java 和 错误页控制器errorcontroller.java

错误页配置类errorpageconfig.java

 1 package cn.temptation.util;
 2 
 3 import org.springframework.boot.web.server.errorpage;
 4 import org.springframework.boot.web.server.errorpageregistrar;
 5 import org.springframework.boot.web.server.errorpageregistry;
 6 import org.springframework.http.httpstatus;
 7 import org.springframework.stereotype.component;
 8 
 9 /**
10  * 错误页配置类
11  */
12 @component
13 public class errorpageconfig implements errorpageregistrar {
14     @override
15     public void registererrorpages(errorpageregistry errorpageregistry) {
16         // 错误类型为401(无访问权限),显示401.html页面
17         errorpage errorpage401 = new errorpage(httpstatus.unauthorized, "/error/401");
18 
19         // 错误类型为404(找不到资源),显示404.html页面
20         errorpage errorpage404 = new errorpage(httpstatus.not_found, "/error/404");
21 
22         // 错误类型为500(服务器内部错误),显示500.html页面
23         errorpage errorpage500 = new errorpage(httpstatus.internal_server_error, "/error/500");
24 
25         errorpageregistry.adderrorpages(errorpage401, errorpage404, errorpage500);
26     }
27 }

 

错误页控制器errorcontroller.java

 1 package cn.temptation.util;
 2 
 3 import org.springframework.stereotype.controller;
 4 import org.springframework.web.bind.annotation.getmapping;
 5 import org.springframework.web.bind.annotation.requestmapping;
 6 
 7 /**
 8  * 错误页控制器
 9  */
10 @controller
11 @requestmapping("/error")
12 public class errorcontroller {
13     // 401页面
14     @getmapping(value = "/401")
15     public string error_401() {
16         return "error/error_401";
17     }
18 
19     // 404页面
20     @getmapping(value = "/404")
21     public string error_404() {
22         return "error/error_404";
23     }
24 
25     // 500页面
26     @getmapping(value = "/500")
27     public string error_500() {
28         return "error/error_500";
29     }
30 }

 

6、编写错误页error_401.html、error_404.html 和 error_500.html

【原】无脑操作:IDEA + maven + Shiro + SpringBoot + JPA + Thymeleaf实现基础认证权限
 1 <!doctype html>
 2 <html>
 3 <head>
 4     <meta charset="utf-8">
 5     <meta http-equiv="refresh" content="5;url=/login">
 6     <title>401</title>
 7     <style>
 8         ::-moz-selection {
 9             background: #b3d4fc;
10             text-shadow: none;
11         }
12 
13         ::selection {
14             background: #b3d4fc;
15             text-shadow: none;
16         }
17 
18         html {
19             padding: 30px 10px;
20             font-size: 20px;
21             line-height: 1.4;
22             color: #737373;
23             background: #f0f0f0;
24             font-family: "helvetica neue", helvetica, arial, sans-serif;
25             -webkit-text-size-adjust: 100%;
26             -ms-text-size-adjust: 100%;
27         }
28 
29         body {
30             max-width: 550px;
31             _width: 550px;
32             padding: 30px 20px 50px;
33             border: 1px solid #b3b3b3;
34             border-radius: 4px;
35             margin: 0 auto;
36             box-shadow: 0 1px 10px #a7a7a7, inset 0 1px 0 #fff;
37             background: #fcfcfc;
38         }
39 
40         h1 {
41             margin: 0 10px;
42             font-size: 50px;
43             text-align: center;
44         }
45 
46         h1 span {
47             color: #bbb;
48         }
49 
50         h3 {
51             margin: 1.5em 0 0.5em;
52         }
53 
54         p {
55             margin: 1em 0;
56         }
57 
58         ul {
59             padding: 0 0 0 40px;
60             margin: 1em 0;
61         }
62 
63         .container {
64             max-width: 500px;
65             _width: 500px;
66             margin: 0 auto;
67         }
68     </style>
69 </head>
70 <body>
71 <div class="container">
72     <h1>没有授权</h1>
73     <p>抱歉,您没有授权访问该页面</p>
74 </div>
75 </body>
76 </html>
error_401
【原】无脑操作:IDEA + maven + Shiro + SpringBoot + JPA + Thymeleaf实现基础认证权限
 1 <!doctype html>
 2 <html>
 3 <head>
 4     <meta charset="utf-8">
 5     <meta http-equiv="refresh" content="5;url=/login">
 6     <title>404</title>
 7     <style>
 8         ::-moz-selection {
 9             background: #b3d4fc;
10             text-shadow: none;
11         }
12 
13         ::selection {
14             background: #b3d4fc;
15             text-shadow: none;
16         }
17 
18         html {
19             padding: 30px 10px;
20             font-size: 20px;
21             line-height: 1.4;
22             color: #737373;
23             background: #f0f0f0;
24             font-family: "helvetica neue", helvetica, arial, sans-serif;
25             -webkit-text-size-adjust: 100%;
26             -ms-text-size-adjust: 100%;
27         }
28 
29         body {
30             max-width: 550px;
31             _width: 550px;
32             padding: 30px 20px 50px;
33             border: 1px solid #b3b3b3;
34             border-radius: 4px;
35             margin: 0 auto;
36             box-shadow: 0 1px 10px #a7a7a7, inset 0 1px 0 #fff;
37             background: #fcfcfc;
38         }
39 
40         h1 {
41             margin: 0 10px;
42             font-size: 50px;
43             text-align: center;
44         }
45 
46         h1 span {
47             color: #bbb;
48         }
49 
50         h3 {
51             margin: 1.5em 0 0.5em;
52         }
53 
54         p {
55             margin: 1em 0;
56         }
57 
58         ul {
59             padding: 0 0 0 40px;
60             margin: 1em 0;
61         }
62 
63         .container {
64             max-width: 500px;
65             _width: 500px;
66             margin: 0 auto;
67         }
68     </style>
69 </head>
70 <body>
71 <div class="container">
72     <h1>没有找到<span>:(</span></h1>
73     <p>抱歉,您试图访问的页面不存在</p>
74     <p>可能是如下原因:</p>
75     <ul>
76         <li>一个错误的地址</li>
77         <li>一个过时的链接</li>
78     </ul>
79 </div>
80 </body>
81 </html>
error_404
【原】无脑操作:IDEA + maven + Shiro + SpringBoot + JPA + Thymeleaf实现基础认证权限
 1 <!doctype html>
 2 <html>
 3 <head>
 4     <meta charset="utf-8">
 5     <meta http-equiv="refresh" content="5;url=/login">
 6     <title>500</title>
 7     <style>
 8         ::-moz-selection {
 9             background: #b3d4fc;
10             text-shadow: none;
11         }
12 
13         ::selection {
14             background: #b3d4fc;
15             text-shadow: none;
16         }
17 
18         html {
19             padding: 30px 10px;
20             font-size: 20px;
21             line-height: 1.4;
22             color: #737373;
23             background: #f0f0f0;
24             font-family: "helvetica neue", helvetica, arial, sans-serif;
25             -webkit-text-size-adjust: 100%;
26             -ms-text-size-adjust: 100%;
27         }
28 
29         body {
30             max-width: 550px;
31             _width: 550px;
32             padding: 30px 20px 50px;
33             border: 1px solid #b3b3b3;
34             border-radius: 4px;
35             margin: 0 auto;
36             box-shadow: 0 1px 10px #a7a7a7, inset 0 1px 0 #fff;
37             background: #fcfcfc;
38         }
39 
40         h1 {
41             margin: 0 10px;
42             font-size: 50px;
43             text-align: center;
44         }
45 
46         h1 span {
47             color: #bbb;
48         }
49 
50         h3 {
51             margin: 1.5em 0 0.5em;
52         }
53 
54         p {
55             margin: 1em 0;
56         }
57 
58         ul {
59             padding: 0 0 0 40px;
60             margin: 1em 0;
61         }
62 
63         .container {
64             max-width: 500px;
65             _width: 500px;
66             margin: 0 auto;
67         }
68     </style>
69 </head>
70 <body>
71 <div class="container">
72     <h1>内部错误</h1>
73     <p>抱歉,服务器上出现了错误......</p>
74 </div>
75 </body>
76 </html>
error_500

 

6、编写登录页面login.html、首页页面index.html、公共模块页page_public.html、领导模块页page_leader.html 和 管理员模块页page_admin.html

【原】无脑操作:IDEA + maven + Shiro + SpringBoot + JPA + Thymeleaf实现基础认证权限
 1 <!doctype html>
 2 <html xmlns:th="http://www.thymeleaf.org">
 3 <head>
 4     <meta charset="utf-8">
 5     <title>系统登录</title>
 6 </head>
 7 <body>
 8 <div th:text="${msg}" style="color: red"></div>
 9 <form action="dologin" method="post">
10 帐号:<input type="text" id="txtusername" name="username" /><br/>
11 密码:<input type="password" id="txtpassword" name="password" /><br/><br/>
12 <input type="submit" value="提交" />&nbsp;<input type="reset" value="重置" />
13 </form>
14 </body>
15 </html>
登录页
【原】无脑操作:IDEA + maven + Shiro + SpringBoot + JPA + Thymeleaf实现基础认证权限
 1 <!doctype html>
 2 <html xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
 3 <head>
 4     <meta charset="utf-8">
 5     <title>系统首页</title>
 6 </head>
 7 <body>
 8 <div th:text="${'欢迎您,' + currentuser}" style="color: red;float: left;"></div>
 9 <div style="color: red;float: right;"><a href="dologout">注销</a></div>
10 <!--
11 thymeleaf中使用shiro标签,具备授权才能看见
12 注意:如果不适用shiro标签,没有授权的访问将产生401响应吗,执行errorpageconfig类 和 errorcontroller类处理
13 -->
14 <!--<div style="clear: both;">公共模块:<a href="publicmodule">公共模块</a></div>-->
15 <!--<div style="clear: both;">领导模块:<a href="leadermodule">领导模块</a></div>-->
16 <!--<div style="clear: both;">管理员模块:<a href="adminmodule">管理员模块</a></div>-->
17 <div style="clear: both;" shiro:haspermission="user:publicmodule">公共模块:<a href="publicmodule">公共模块</a></div>
18 <div style="clear: both;" shiro:haspermission="user:leadermodule">领导模块:<a href="leadermodule">领导模块</a></div>
19 <div style="clear: both;" shiro:haspermission="user:adminmodule">管理员模块:<a href="adminmodule">管理员模块</a></div>
20 </body>
21 </html>
首页
【原】无脑操作:IDEA + maven + Shiro + SpringBoot + JPA + Thymeleaf实现基础认证权限
 1 <!doctype html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="utf-8">
 5     <title>公共模块</title>
 6 </head>
 7 <body>
 8 公共模块(管理员、领导、员工均可访问)
 9 </body>
10 </html>
公共模块页
【原】无脑操作:IDEA + maven + Shiro + SpringBoot + JPA + Thymeleaf实现基础认证权限
 1 <!doctype html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="utf-8">
 5     <title>领导模块</title>
 6 </head>
 7 <body>
 8 领导模块(管理员、领导均可访问)
 9 </body>
10 </html>
领导模块页
【原】无脑操作:IDEA + maven + Shiro + SpringBoot + JPA + Thymeleaf实现基础认证权限
 1 <!doctype html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="utf-8">
 5     <title>管理员模块</title>
 6 </head>
 7 <body>
 8 管理员模块(管理员可访问)
 9 </body>
10 </html>
管理员模块页

 

7、编写shiro框架用配置类shiroconfig.java 和 自定义realm类myrealm.java

配置类shiroconfig.java

  1 package cn.temptation.shiro;
  2 
  3 import at.pollux.thymeleaf.shiro.dialect.shirodialect;
  4 import cn.temptation.dao.resourcedao;
  5 import cn.temptation.domain.resource;
  6 import org.apache.shiro.spring.web.shirofilterfactorybean;
  7 import org.apache.shiro.web.mgt.defaultwebsecuritymanager;
  8 import org.springframework.beans.factory.annotation.autowired;
  9 import org.springframework.beans.factory.annotation.qualifier;
 10 import org.springframework.context.annotation.bean;
 11 import org.springframework.context.annotation.configuration;
 12 
 13 import java.util.linkedhashmap;
 14 import java.util.list;
 15 import java.util.map;
 16 
 17 /**
 18  * shiro配置类
 19  */
 20 @configuration
 21 public class shiroconfig {
 22     @autowired
 23     private resourcedao resourcedao;
 24 
 25     // 1、创建shirofilterfactorybean
 26     @bean
 27     public shirofilterfactorybean getshirofilterfactorybean(@qualifier("securitymanager") defaultwebsecuritymanager defaultwebsecuritymanager) {
 28         shirofilterfactorybean shirofilterfactorybean = new shirofilterfactorybean();
 29         // 设置安全管理器
 30         shirofilterfactorybean.setsecuritymanager(defaultwebsecuritymanager);
 31 
 32         // 设置登录跳转页面
 33         shirofilterfactorybean.setloginurl("/login");
 34 
 35         /**
 36          * shiro内置过滤器:实现权限相关的拦截
 37          *      常用过滤器:
 38          *          anon(认证用):无需认证(登录)即可访问
 39          *          authc(认证用):必须认证才可访问
 40          *          user(少用):使用rememberme功能可以访问
 41          *          perms(授权用):必须得到资源权限才可访问
 42          *          role(授权用):必须得到角色权限才可访问
 43          */
 44         map<string, string> filtermap = new linkedhashmap<>();
 45 
 46         // 放行登录请求
 47         filtermap.put("/dologin", "anon");
 48 
 49         // 配置退出过滤器,退出代码shiro已经实现
 50         filtermap.put("/logout", "logout");
 51 
 52         // 配置授权过滤器
 53 
 54         // 先代码写死,测试下
 55 //        filtermap.put("/publicmodule", "perms[user:publicmodule]");
 56 //        filtermap.put("/leadermodule", "perms[user:leadermodule]");
 57 //        filtermap.put("/adminmodule", "perms[user:adminmodule]");
 58 
 59         // 获取所有资源,并配置需要进行授权过滤的资源
 60         list<resource> resources = resourcedao.findall();
 61         resources.foreach(item -> {
 62             if (!"".equals(item.getresourceurl())) {
 63                 filtermap.put("/" + item.getresourceurl(), "perms[user:" + item.getresourceurl() + "]");
 64             }
 65         });
 66 
 67         // 过滤链定义,从上向下顺序执行,一般将/*放在最下边
 68         filtermap.put("/*", "authc");
 69 
 70         // 设置未授权界面
 71         shirofilterfactorybean.setunauthorizedurl("/error/401");
 72 
 73         shirofilterfactorybean.setfilterchaindefinitionmap(filtermap);
 74 
 75         return shirofilterfactorybean;
 76     }
 77 
 78     // 2、创建defaultwebsecuritymanager
 79     @bean(name = "securitymanager")
 80     public defaultwebsecuritymanager getdefaultwebsecuritymanager(@qualifier("myrealm") myrealm myrealm) {
 81         defaultwebsecuritymanager defaultwebsecuritymanager = new defaultwebsecuritymanager();
 82 
 83         // 关联realm
 84         defaultwebsecuritymanager.setrealm(myrealm);
 85 
 86         return defaultwebsecuritymanager;
 87     }
 88 
 89     // 3、创建realm
 90     @bean(name = "myrealm")
 91     public myrealm getrealm() {
 92         return new myrealm();
 93     }
 94 
 95     // 4、配置shirodialect后,可以在页面使用shiro标签
 96     @bean
 97     public shirodialect getshirodialect() {
 98         return new shirodialect();
 99     }
100 }

 

自定义realm类myrealm.java

 1 package cn.temptation.shiro;
 2 
 3 import cn.temptation.dao.resourcedao;
 4 import cn.temptation.dao.userdao;
 5 import cn.temptation.domain.user;
 6 import org.apache.shiro.authc.*;
 7 import org.apache.shiro.authz.authorizationinfo;
 8 import org.apache.shiro.authz.simpleauthorizationinfo;
 9 import org.apache.shiro.realm.authorizingrealm;
10 import org.apache.shiro.subject.principalcollection;
11 import org.springframework.beans.factory.annotation.autowired;
12 
13 import java.util.list;
14 
15 /**
16  * 自定义realm
17  */
18 public class myrealm extends authorizingrealm {
19     @autowired
20     private userdao userdao;
21     @autowired
22     private resourcedao resourcedao;
23 
24     // 授权处理
25     @override
26     protected authorizationinfo dogetauthorizationinfo(principalcollection principalcollection) {
27         // 获取当前登录获得认证的用户
28         user user = (user) principalcollection.getprimaryprincipal();
29         // 下句语句会抛出异常交由errorcontroller类根据errorpageconfig类中注册的响应码和错误页面处理
30 //        system.out.println(1 / 0);
31 
32         if (user != null) {
33             // 给资源授权
34             simpleauthorizationinfo info = new simpleauthorizationinfo();
35 
36             // 先代码写死,测试下
37 //            info.addstringpermission("user:publicmodule");
38 //            info.addstringpermission("user:leadermodule");
39 //            info.addstringpermission("user:adminmodule");
40 
41             // 根据获得认证的用户编号查询该用户具备的资源url集合
42             list<string> resourceurls = resourcedao.findbyuserid(user.getuserid());
43 
44             // 遍历集合,组装成满足授权过滤器过滤格式,并添加到资源信息中
45             resourceurls.foreach(item -> info.addstringpermission("user:" + item));
46 
47             return info;
48         }
49 
50         return null;
51     }
52 
53     // 认证处理
54     @override
55     protected authenticationinfo dogetauthenticationinfo(authenticationtoken authenticationtoken) throws authenticationexception {
56         // 编写shiro判断逻辑,判断账号和密码
57         // 1、判断账号
58         usernamepasswordtoken token = (usernamepasswordtoken) authenticationtoken;
59 
60         user user = userdao.findbyusername(token.getusername());
61         if (user == null) {
62             // 账号错误,shiro底层会抛出unknownaccountexception异常
63             return null;
64         }
65 
66         // 2、判断密码
67         // 只做认证,principal可以设置为空字符串
68 //        return new simpleauthenticationinfo("", user.getpassword(), "");
69         // 认证后做授权处理,需要将获得认证的用户对象赋值给principal,授权处理时会用到
70         return new simpleauthenticationinfo(user, user.getpassword(), "");
71     }
72 }

 

8、编写用户实体类user.java、角色实体类role.java 和 资源实体类resource.java

用户实体类user.java

 1 package cn.temptation.domain;
 2 
 3 import javax.persistence.*;
 4 
 5 @entity
 6 @table(name = "sys_user")
 7 public class user {
 8     @id
 9     @generatedvalue(strategy = generationtype.identity)
10     @column(name = "userid")
11     private integer userid;
12 
13     @column(name = "username")
14     private string username;
15 
16     @column(name = "password")
17     private string password;
18 
19     @manytoone
20     @joincolumn(name = "roleid", foreignkey = @foreignkey(name = "none"))
21     private role role;
22 
23     public integer getuserid() {
24         return userid;
25     }
26 
27     public void setuserid(integer userid) {
28         this.userid = userid;
29     }
30 
31     public string getusername() {
32         return username;
33     }
34 
35     public void setusername(string username) {
36         this.username = username;
37     }
38 
39     public string getpassword() {
40         return password;
41     }
42 
43     public void setpassword(string password) {
44         this.password = password;
45     }
46 
47     public role getrole() {
48         return role;
49     }
50 
51     public void setrole(role role) {
52         this.role = role;
53     }
54 }

 

角色实体类role.java

 1 package cn.temptation.domain;
 2 
 3 import javax.persistence.*;
 4 import java.util.set;
 5 
 6 @entity
 7 @table(name = "sys_role")
 8 public class role {
 9     @id
10     @generatedvalue(strategy = generationtype.identity)
11     @column(name = "roleid")
12     private integer roleid;
13 
14     @column(name = "rolename")
15     private string rolename;
16 
17     @manytomany
18     @jointable(name = "sys_role_resource",
19             joincolumns = {@joincolumn(name = "roleid", referencedcolumnname = "roleid", foreignkey = @foreignkey(name = "none"))},
20             inversejoincolumns = {@joincolumn(name = "resourceid", referencedcolumnname = "resourceid", foreignkey = @foreignkey(name = "none"))})
21     private set<resource> resources;
22 
23     public integer getroleid() {
24         return roleid;
25     }
26 
27     public void setroleid(integer roleid) {
28         this.roleid = roleid;
29     }
30 
31     public string getrolename() {
32         return rolename;
33     }
34 
35     public void setrolename(string rolename) {
36         this.rolename = rolename;
37     }
38 }

 

资源实体类resource.java

 1 package cn.temptation.domain;
 2 
 3 import javax.persistence.*;
 4 
 5 @entity
 6 @table(name = "sys_resource")
 7 public class resource {
 8     @id
 9     @generatedvalue(strategy = generationtype.identity)
10     @column(name = "resourceid")
11     private integer resourceid;
12 
13     @column(name = "resourcename")
14     private string resourcename;
15 
16     @column(name = "resourceurl")
17     private string resourceurl;
18 
19     public integer getresourceid() {
20         return resourceid;
21     }
22 
23     public void setresourceid(integer resourceid) {
24         this.resourceid = resourceid;
25     }
26 
27     public string getresourcename() {
28         return resourcename;
29     }
30 
31     public void setresourcename(string resourcename) {
32         this.resourcename = resourcename;
33     }
34 
35     public string getresourceurl() {
36         return resourceurl;
37     }
38 
39     public void setresourceurl(string resourceurl) {
40         this.resourceurl = resourceurl;
41     }
42 }

 

9、编写用户控制器类usercontroller.java

 1 package cn.temptation.web;
 2 
 3 import org.apache.shiro.securityutils;
 4 import org.apache.shiro.authc.incorrectcredentialsexception;
 5 import org.apache.shiro.authc.unknownaccountexception;
 6 import org.apache.shiro.authc.usernamepasswordtoken;
 7 import org.apache.shiro.subject.subject;
 8 import org.springframework.stereotype.controller;
 9 import org.springframework.ui.model;
10 import org.springframework.web.bind.annotation.requestmapping;
11 
12 @controller
13 public class usercontroller {
14     // 访问登录页
15     @requestmapping("/login")
16     public string login() {
17         // 下句语句会抛出异常交由globalexceptionhandler类的errorhandler方法处理
18 //        system.out.println(1 / 0);
19 
20         return "login";
21     }
22 
23     // 访问首页
24     @requestmapping("/index")
25     public string index() {
26         return "index";
27     }
28 
29     // 访问公共模块
30     @requestmapping("/publicmodule")
31     public string publicmodule() {
32         return "page_public";
33     }
34 
35     // 访问私密模块
36     @requestmapping("/privatemodule")
37     public string privatemodule() {
38         return "page_leader";
39     }
40 
41     // 登录处理
42     @requestmapping("/dologin")
43     public string dologin(string username, string password, model model) {
44         // 使用shiro编写认证处理
45         // 1、获取subject
46         subject subject = securityutils.getsubject();
47 
48         // 2、封装用户数据
49         usernamepasswordtoken token = new usernamepasswordtoken(username, password);
50 
51         // 3、执行登录
52         try {
53             // 登录成功
54             subject.login(token);
55 
56             // 返回当前用户的帐号
57             model.addattribute("currentuser", token.getusername());
58 
59             return "index";
60         } catch (unknownaccountexception exception) {
61             // 返回错误信息
62             model.addattribute("msg", "账号错误!");
63 
64             return "login";
65         } catch (incorrectcredentialsexception exception) {
66             // 返回错误信息
67             model.addattribute("msg", "密码错误!");
68 
69             return "login";
70         }
71     }
72 
73     // 注销处理
74     @requestmapping("/dologout")
75     public string dologout() {
76         // 1、获取subject
77         subject subject = securityutils.getsubject();
78 
79         // 2、执行注销
80         try {
81             subject.logout();
82         } catch (exception ex) {
83             ex.printstacktrace();
84         } finally {
85             return "login";
86         }
87     }
88 }

 

10、编写用户数据访问接口userdao.java、角色数据访问接口roledao.java 和 资源数据访问接口resourcedao.java

用户数据访问接口userdao.java

 1 package cn.temptation.dao;
 2 
 3 import cn.temptation.domain.user;
 4 import org.springframework.data.jpa.repository.jparepository;
 5 import org.springframework.data.jpa.repository.query;
 6 import org.springframework.data.repository.query.param;
 7 
 8 public interface userdao extends jparepository<user, integer> {
 9     // 根据账号查询用户
10     @query(value = "select * from sys_user where username=:username", nativequery = true)
11     user findbyusername(@param("username") string username);
12 }

 

角色数据访问接口roledao.java

1 package cn.temptation.dao;
2 
3 import cn.temptation.domain.role;
4 import org.springframework.data.jpa.repository.jparepository;
5 
6 public interface roledao extends jparepository<role, integer> {
7 
8 }

 

资源数据访问接口resourcedao.java

 1 package cn.temptation.dao;
 2 
 3 import cn.temptation.domain.resource;
 4 import org.springframework.data.jpa.repository.jparepository;
 5 import org.springframework.data.jpa.repository.query;
 6 import org.springframework.data.repository.query.param;
 7 
 8 import java.util.list;
 9 
10 public interface resourcedao extends jparepository<resource, integer> {
11     @query(value = "select rs.resourceurl from sys_role_resource as rr " +
12             "inner join sys_resource as rs on rr.resourceid = rs.resourceid " +
13             "inner join sys_role as r on rr.roleid = r.roleid " +
14             "inner join sys_user as u on u.roleid = r.roleid where u.userid = :userid ", nativequery = true)
15     list<string> findbyuserid(@param("userid") integer userid);
16 }

 

11、项目结构

【原】无脑操作:IDEA + maven + Shiro + SpringBoot + JPA + Thymeleaf实现基础认证权限

 

 

12、运行效果

【原】无脑操作:IDEA + maven + Shiro + SpringBoot + JPA + Thymeleaf实现基础认证权限

 

【原】无脑操作:IDEA + maven + Shiro + SpringBoot + JPA + Thymeleaf实现基础认证权限

【原】无脑操作:IDEA + maven + Shiro + SpringBoot + JPA + Thymeleaf实现基础认证权限