springBoot + springsecurity +MySQL8 +Thymeleaf 实现用户权限系统分析

熊孩纸 阅读:250 2021-03-31 18:14:49 评论:0

第一步:项目整体结构说明:

基于springboot + springsecurity + mysql + themleaf 构建用户权限系统项目结构说明:

第二步:依赖的数据库脚本:

建库脚本:

DROP TABLE IF EXISTS `u_permission`; 
CREATE TABLE IF NOT EXISTS `u_permission` ( 
  `id` bigint(20) NOT NULL AUTO_INCREMENT, 
  `url` varchar(256) DEFAULT NULL COMMENT 'url地址', 
  `name` varchar(64) DEFAULT NULL COMMENT 'url描述', 
  PRIMARY KEY (`id`) 
) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; 
 
DROP TABLE IF EXISTS `u_role`; 
CREATE TABLE IF NOT EXISTS `u_role` ( 
  `id` bigint(20) NOT NULL AUTO_INCREMENT, 
  `name` varchar(32) DEFAULT NULL COMMENT '角色名称', 
  `type` varchar(10) DEFAULT NULL COMMENT '角色类型', 
  PRIMARY KEY (`id`) 
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; 
 
DROP TABLE IF EXISTS `u_role_permission`; 
CREATE TABLE IF NOT EXISTS `u_role_permission` ( 
  `rid` bigint(20) DEFAULT NULL COMMENT '角色ID', 
  `pid` bigint(20) DEFAULT NULL COMMENT '权限ID' 
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; 
 
DROP TABLE IF EXISTS `u_user`; 
CREATE TABLE IF NOT EXISTS `u_user` ( 
  `id` bigint(20) NOT NULL AUTO_INCREMENT, 
  `nickname` varchar(20) DEFAULT NULL COMMENT '用户昵称', 
  `email` varchar(128) DEFAULT NULL COMMENT '邮箱|登录帐号', 
  `pswd` varchar(32) DEFAULT NULL COMMENT '密码', 
  `create_time` datetime DEFAULT NULL COMMENT '创建时间', 
  `last_login_time` datetime DEFAULT NULL COMMENT '最后登录时间', 
  `status` bigint(1) DEFAULT '1' COMMENT '1:有效,0:禁止登录', 
  PRIMARY KEY (`id`) 
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; 
 
 
DROP TABLE IF EXISTS `u_user_role`; 
CREATE TABLE IF NOT EXISTS `u_user_role` ( 
  `uid` bigint(20) DEFAULT NULL COMMENT '用户ID', 
  `rid` bigint(20) DEFAULT NULL COMMENT '角色ID' 
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

初始化数据:

INSERT INTO `u_permission` (`id`, `url`, `name`) VALUES 
	(1, 'userInfo/userList', '用户管理'), 
	(2, 'userInfo/userAdd', '用户添加'), 
	(3, 'userInfo/userDel', '用户删除'); 
INSERT INTO `u_role` (`id`, `name`, `type`) VALUES 
	(1, '管理员', '1'), 
	(2, '用户', '2'); 
INSERT INTO `u_role_permission` (`rid`, `pid`) VALUES 
	(1, 1), 
	(1, 2), 
	(1, 3); 
INSERT INTO `u_user` (`id`, `nickname`, `email`, `pswd`, `create_time`, `last_login_time`, `status`) VALUES 
	(1, 'admin', [email protected]', '1', '2019-04-27 22:44:44', NULL, 1); 
INSERT INTO `u_user_role` (`uid`, `rid`) VALUES 
	(1, 1);

第三步:项目依赖的pom 文件:

boo-security 的pom.xml文件

<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.zzg</groupId> 
	<artifactId>boot-security</artifactId> 
	<version>0.0.1-SNAPSHOT</version> 
	<packaging>pom</packaging> 
 
	<parent> 
		<groupId>org.springframework.boot</groupId> 
		<artifactId>spring-boot-starter-parent</artifactId> 
		<version>2.1.2.RELEASE</version> 
	</parent> 
	<!--springboot 项目基础依赖 --> 
	<dependencies> 
		<!--web 模块依赖 --> 
		<dependency> 
			<groupId>org.springframework.boot</groupId> 
			<artifactId>spring-boot-starter-web</artifactId> 
		</dependency> 
		<!--web 热部署 --> 
		<dependency> 
			<groupId>org.springframework.boot</groupId> 
			<artifactId>spring-boot-devtools</artifactId> 
			<optional>true</optional> 
		</dependency> 
		<!--web 单元测试 --> 
		<dependency> 
			<groupId>org.springframework.boot</groupId> 
			<artifactId>spring-boot-starter-test</artifactId> 
			<scope>test</scope> 
		</dependency> 
		<!--common-lang 常用工具包 --> 
		<dependency> 
			<groupId>commons-lang</groupId> 
			<artifactId>commons-lang</artifactId> 
			<version>2.6</version> 
		</dependency> 
		<!--commons-codec 加密工具包 --> 
		<dependency> 
			<groupId>commons-codec</groupId> 
			<artifactId>commons-codec</artifactId> 
			<version>1.10</version> 
		</dependency> 
	</dependencies> 
 
	<modules> 
		<module>boot-security-api</module> 
		<module>boot-security-dao</module> 
		<module>boot-security-controller</module> 
	</modules> 
</project>

boo-security-api 的pom.xml文件

<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> 
  <parent> 
    <groupId>com.zzg</groupId> 
    <artifactId>boot-security</artifactId> 
    <version>0.0.1-SNAPSHOT</version> 
  </parent> 
  <artifactId>boot-security-api</artifactId> 
</project>

boo-security-dao 的pom.xml文件

<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> 
	<parent> 
		<groupId>com.zzg</groupId> 
		<artifactId>boot-security</artifactId> 
		<version>0.0.1-SNAPSHOT</version> 
	</parent> 
	<artifactId>boot-security-dao</artifactId> 
 
 
	<dependencies> 
		<!--依赖api 层 --> 
		<dependency> 
			<groupId>com.zzg</groupId> 
			<artifactId>boot-security-api</artifactId> 
			<version>0.0.1-SNAPSHOT</version> 
		</dependency> 
	</dependencies> 
 
	<!--集成mybatis-generator 自动生成组件 --> 
	<build> 
		<plugins> 
			<plugin> 
				<groupId>org.mybatis.generator</groupId> 
				<artifactId>mybatis-generator-maven-plugin</artifactId> 
				<version>1.3.7</version> 
				<dependencies> 
					<dependency> 
						<groupId>mysql</groupId> 
						<artifactId>mysql-connector-java</artifactId> 
						<version>8.0.12</version> 
					</dependency> 
					<dependency> 
						<groupId>org.mybatis.generator</groupId> 
						<artifactId>mybatis-generator-core</artifactId> 
						<version>1.3.7</version> 
					</dependency> 
				</dependencies> 
				<executions> 
					<execution> 
						<id>Generate MyBatis Artifacts</id> 
						<phase>package</phase> 
						<goals> 
							<goal>generate</goal> 
						</goals> 
					</execution> 
				</executions> 
				<configuration> 
					<!--允许移动生成的文件 --> 
					<verbose>true</verbose> 
					<!-- 是否覆盖 --> 
					<overwrite>true</overwrite> 
					<!-- 自动生成的配置 --> 
					<configurationFile>src/main/resources/generatorConfig.xml</configurationFile> 
				</configuration> 
			</plugin> 
		</plugins> 
	</build> 
 
</project>

boo-security-controller 的pom.xml文件

<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> 
  <parent> 
    <groupId>com.zzg</groupId> 
    <artifactId>boot-security</artifactId> 
    <version>0.0.1-SNAPSHOT</version> 
  </parent> 
  <artifactId>boot-security-controller</artifactId> 
   
  <dependencies> 
  	<!--依赖api层 --> 
		<dependency> 
			<groupId>com.zzg</groupId> 
			<artifactId>boot-security-api</artifactId> 
			<version>0.0.1-SNAPSHOT</version> 
		</dependency> 
		<!--dao 层依赖  --> 
		<dependency> 
			<groupId>com.zzg</groupId> 
			<artifactId>boot-security-dao</artifactId> 
			<version>0.0.1-SNAPSHOT</version> 
		</dependency> 
		<!--springboot 与 mybatis 集成 --> 
		<dependency> 
			<groupId>org.mybatis.spring.boot</groupId> 
			<artifactId>mybatis-spring-boot-starter</artifactId> 
			<version>1.3.2</version> 
		</dependency> 
		<!-- 数据库连接池druid --> 
		<dependency> 
			<groupId>com.alibaba</groupId> 
			<artifactId>druid-spring-boot-starter</artifactId> 
			<version>1.1.10</version> 
		</dependency> 
		<!--mysql 驱动程序 --> 
		<dependency> 
			<groupId>mysql</groupId> 
			<artifactId>mysql-connector-java</artifactId> 
			<version>8.0.12</version> 
		</dependency> 
		<!--apache security 依赖jar --> 
		 <dependency> 
            <groupId>org.springframework.boot</groupId> 
            <artifactId>spring-boot-starter-security</artifactId> 
        </dependency> 
		<!--thymeleaf 模板依赖 --> 
		<dependency> 
			<groupId>org.springframework.boot</groupId> 
			<artifactId>spring-boot-starter-thymeleaf</artifactId> 
		</dependency> 
		<dependency> 
			<groupId>net.sourceforge.nekohtml</groupId> 
			<artifactId>nekohtml</artifactId> 
			<version>1.9.22</version> 
		</dependency> 
  </dependencies> 
</project>

第四步:用户权限系统设计mapper接口定义、mapper映射文件、service 接口定义、service 接口实现、entity 实体文件。(boot-security-api[实体对象和service接口定义]、boot-security-dao[mapper接口定义和mapper映射文件]、boot-security-controller[service 接口实现])

请直接参考改项目github 地址:https://github.com/zhouzhiwengang/boot-security.git

第五步:编辑themleaf 模板引擎涉及的Html 文件(resource/templates文件夹下涉及的HTML文件)

请直接参考改项目github 地址:https://github.com/zhouzhiwengang/boot-security.git

第六步:编辑application.properties 、logback.xml 和SpringBoot 程序入口

application.properties

# \u5B9A\u4E49logback \u914D\u7F6E\u6587\u4EF6 
logging.config=classpath:logback.xml 
#mybatis xml \u6587\u4EF6\u914D\u7F6E 
mybatis.mapper-locations=classpath:mapper/*Mapper.xml 
# Thymeleaf setting 
thymeleaf.cache=false 
thymeleaf.mode=LEGACYHTML5 
# MyBatis mysql8 \u914D\u7F6E 
spring.datasource.url=jdbc:mysql://192.168.1.73:3306/boot-security?serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=true 
spring.datasource.username=root 
spring.datasource.password=digipower 
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver 
  
# Druid \u914D\u7F6E 
# \u521D\u59CB\u5316\u65F6\u5EFA\u7ACB\u7269\u7406\u8FDE\u63A5\u7684\u4E2A\u6570 
spring.datasource.druid.initial-size=5 
# \u6700\u5927\u8FDE\u63A5\u6C60\u6570\u91CF 
spring.datasource.druid.max-active=30 
# \u6700\u5C0F\u8FDE\u63A5\u6C60\u6570\u91CF 
spring.datasource.druid.min-idle=5 
# \u83B7\u53D6\u8FDE\u63A5\u65F6\u6700\u5927\u7B49\u5F85\u65F6\u95F4\uFF0C\u5355\u4F4D\u6BEB\u79D2 
spring.datasource.druid.max-wait=60000 
# \u914D\u7F6E\u95F4\u9694\u591A\u4E45\u624D\u8FDB\u884C\u4E00\u6B21\u68C0\u6D4B\uFF0C\u68C0\u6D4B\u9700\u8981\u5173\u95ED\u7684\u7A7A\u95F2\u8FDE\u63A5\uFF0C\u5355\u4F4D\u662F\u6BEB\u79D2 
spring.datasource.druid.time-between-eviction-runs-millis=60000 
# \u8FDE\u63A5\u4FDD\u6301\u7A7A\u95F2\u800C\u4E0D\u88AB\u9A71\u9010\u7684\u6700\u5C0F\u65F6\u95F4 
spring.datasource.druid.min-evictable-idle-time-millis=300000 
# \u7528\u6765\u68C0\u6D4B\u8FDE\u63A5\u662F\u5426\u6709\u6548\u7684sql\uFF0C\u8981\u6C42\u662F\u4E00\u4E2A\u67E5\u8BE2\u8BED\u53E5 
spring.datasource.druid.validation-query=SELECT 1 FROM DUAL 
# \u5EFA\u8BAE\u914D\u7F6E\u4E3Atrue\uFF0C\u4E0D\u5F71\u54CD\u6027\u80FD\uFF0C\u5E76\u4E14\u4FDD\u8BC1\u5B89\u5168\u6027\u3002\u7533\u8BF7\u8FDE\u63A5\u7684\u65F6\u5019\u68C0\u6D4B\uFF0C\u5982\u679C\u7A7A\u95F2\u65F6\u95F4\u5927\u4E8EtimeBetweenEvictionRunsMillis\uFF0C\u6267\u884CvalidationQuery\u68C0\u6D4B\u8FDE\u63A5\u662F\u5426\u6709\u6548\u3002 
spring.datasource.druid.test-while-idle=true 
# \u7533\u8BF7\u8FDE\u63A5\u65F6\u6267\u884CvalidationQuery\u68C0\u6D4B\u8FDE\u63A5\u662F\u5426\u6709\u6548\uFF0C\u505A\u4E86\u8FD9\u4E2A\u914D\u7F6E\u4F1A\u964D\u4F4E\u6027\u80FD\u3002 
spring.datasource.druid.test-on-borrow=false 
# \u5F52\u8FD8\u8FDE\u63A5\u65F6\u6267\u884CvalidationQuery\u68C0\u6D4B\u8FDE\u63A5\u662F\u5426\u6709\u6548\uFF0C\u505A\u4E86\u8FD9\u4E2A\u914D\u7F6E\u4F1A\u964D\u4F4E\u6027\u80FD\u3002 
spring.datasource.druid.test-on-return=false 
# \u662F\u5426\u7F13\u5B58preparedStatement\uFF0C\u4E5F\u5C31\u662FPSCache\u3002PSCache\u5BF9\u652F\u6301\u6E38\u6807\u7684\u6570\u636E\u5E93\u6027\u80FD\u63D0\u5347\u5DE8\u5927\uFF0C\u6BD4\u5982\u8BF4oracle\u3002\u5728mysql\u4E0B\u5EFA\u8BAE\u5173\u95ED\u3002 
spring.datasource.druid.pool-prepared-statements=true 
# \u8981\u542F\u7528PSCache\uFF0C\u5FC5\u987B\u914D\u7F6E\u5927\u4E8E0\uFF0C\u5F53\u5927\u4E8E0\u65F6\uFF0CpoolPreparedStatements\u81EA\u52A8\u89E6\u53D1\u4FEE\u6539\u4E3Atrue\u3002 
spring.datasource.druid.max-pool-prepared-statement-per-connection-size=50 
# \u914D\u7F6E\u76D1\u63A7\u7EDF\u8BA1\u62E6\u622A\u7684filters\uFF0C\u53BB\u6389\u540E\u76D1\u63A7\u754C\u9762sql\u65E0\u6CD5\u7EDF\u8BA1 
spring.datasource.druid.filters=stat,wall 
# \u901A\u8FC7connectProperties\u5C5E\u6027\u6765\u6253\u5F00mergeSql\u529F\u80FD\uFF1B\u6162SQL\u8BB0\u5F55 
spring.datasource.druid.connection-properties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500 
# \u5408\u5E76\u591A\u4E2ADruidDataSource\u7684\u76D1\u63A7\u6570\u636E 
spring.datasource.druid.use-global-data-source-stat=true

logback.xml

<?xml version="1.0" encoding="UTF-8"?>  
   
<!-- 从高到地低 OFF 、 FATAL 、 ERROR 、 WARN 、 INFO 、 DEBUG 、 TRACE 、 ALL -->   
<!-- 日志输出规则  根据当前ROOT 级别,日志输出时,级别高于root默认的级别时  会输出 -->   
<!-- 以下  每个配置的 filter 是过滤掉输出文件里面,会出现高级别文件,依然出现低级别的日志信息,通过filter 过滤只记录本级别的日志-->   
   
   
<!-- 属性描述 scan:性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位, 
默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。    
    debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->   
<configuration scan="true" scanPeriod="60 seconds" debug="false">   
    <!-- 定义日志文件 输入位置 -->   
    <property name="log_dir" value="/logs/boot-security" />   
    <!-- 日志最大的历史 30天 -->   
    <property name="maxHistory" value="30"/>   
   
   
    <!-- ConsoleAppender 控制台输出日志 -->   
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">   
        <!-- 对日志进行格式化 -->   
        <encoder>   
            <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger -%msg%n</pattern>   
        </encoder>   
    </appender>   
       
       
    <!-- ERROR级别日志 -->   
    <!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 RollingFileAppender-->   
    <appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">   
        <!-- 过滤器,只记录WARN级别的日志 -->   
        <filter class="ch.qos.logback.classic.filter.LevelFilter">   
            <level>ERROR</level>   
            <onMatch>ACCEPT</onMatch>   
            <onMismatch>DENY</onMismatch>   
        </filter>   
        <!-- 最常用的滚动策略,它根据时间来制定滚动策略.既负责滚动也负责出发滚动 -->   
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">   
            <!--日志输出位置  可相对、和绝对路径 -->   
            <fileNamePattern>${log_dir}/%d{yyyy-MM-dd}/mysql-boot-error-log.log</fileNamePattern>   
            <!-- 可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件假设设置每个月滚动,且<maxHistory>是6,   
            则只保存最近6个月的文件,删除之前的旧文件。注意,删除旧文件是,那些为了归档而创建的目录也会被删除-->   
            <maxHistory>${maxHistory}</maxHistory>   
        </rollingPolicy>   
           
        <!-- 按照固定窗口模式生成日志文件,当文件大于20MB时,生成新的日志文件。窗口大小是1到3,当保存了3个归档文件后,将覆盖最早的日志。    
        <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">      
          <fileNamePattern>${log_dir}/%d{yyyy-MM-dd}/.log.zip</fileNamePattern>      
          <minIndex>1</minIndex>      
          <maxIndex>3</maxIndex>      
        </rollingPolicy>   -->   
        <!-- 查看当前活动文件的大小,如果超过指定大小会告知RollingFileAppender 触发当前活动文件滚动    
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">      
            <maxFileSize>5MB</maxFileSize>      
        </triggeringPolicy>   -->   
           
        <encoder>   
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>   
        </encoder>   
    </appender>   
       
       
    <!-- WARN级别日志 appender -->   
    <appender name="WARN" class="ch.qos.logback.core.rolling.RollingFileAppender">   
        <!-- 过滤器,只记录WARN级别的日志 -->   
        <filter class="ch.qos.logback.classic.filter.LevelFilter">   
            <level>WARN</level>   
            <onMatch>ACCEPT</onMatch>   
            <onMismatch>DENY</onMismatch>   
        </filter>   
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">   
            <fileNamePattern>${log_dir}/%d{yyyy-MM-dd}/mysql-boot-warn-log.log   
            </fileNamePattern>   
            <maxHistory>${maxHistory}</maxHistory>   
        </rollingPolicy>   
        <encoder>   
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>   
        </encoder>   
    </appender>   
       
       
    <!-- INFO级别日志 appender -->   
    <appender name="INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">   
        <!-- 过滤器,只记录INFO级别的日志 -->   
        <filter class="ch.qos.logback.classic.filter.LevelFilter">   
            <level>INFO</level>   
            <onMatch>ACCEPT</onMatch>   
            <onMismatch>DENY</onMismatch>   
        </filter>   
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">   
            <fileNamePattern>${log_dir}/%d{yyyy-MM-dd}/myql-boot-info-log.log   
            </fileNamePattern>   
            <maxHistory>${maxHistory}</maxHistory>   
        </rollingPolicy>   
        <encoder>   
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>   
        </encoder>   
    </appender>   
       
       
    <!-- DEBUG级别日志 appender -->   
    <appender name="DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">   
        <!--过滤器,仅记录DEBUG级别的日志  --> 
        <filter class="ch.qos.logback.classic.filter.LevelFilter">   
            <level>DEBUG</level>   
            <onMatch>ACCEPT</onMatch>   
            <onMismatch>DENY</onMismatch>   
        </filter>   
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">   
            <fileNamePattern>${log_dir}/%d{yyyy-MM-dd}/mysql-boot-debug-log.log   
            </fileNamePattern>   
            <maxHistory>${maxHistory}</maxHistory>   
        </rollingPolicy>   
        <encoder>   
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>   
        </encoder>   
    </appender>   
     
     <!-- 需要记录日志的包  --> 
    <logger name="java.sql.PreparedStatement" value="DEBUG" />     
    <logger name="java.sql.Connection" value="DEBUG" />     
    <logger name="java.sql.Statement" value="DEBUG" />     
    <logger name="com.ibatis" value="DEBUG" />     
    <logger name="com.ibatis.common.jdbc.SimpleDataSource" value="DEBUG" />     
    <logger name="com.ibatis.common.jdbc.ScriptRunner" level="DEBUG"/>     
    <logger name="com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate" value="DEBUG" />     
    <logger name="org.springframework.web" level="DEBUG"/> 
    <logger name="com.zzg" level="DEBUG"/> 
		 
       
    <!-- root级别   DEBUG -->   
    <root level="INFO">   
        <!-- 控制台输出 -->   
        <appender-ref ref="STDOUT" />   
        <!-- 文件输出 -->   
        <appender-ref ref="ERROR" />   
        <appender-ref ref="INFO" />   
        <appender-ref ref="WARN" />   
        <appender-ref ref="DEBUG" />   
    </root>   
</configuration>

springboot 程序入口:

package com.zzg; 
 
import org.mybatis.spring.annotation.MapperScan; 
import org.springframework.boot.SpringApplication; 
import org.springframework.boot.autoconfigure.SpringBootApplication; 
 
@SpringBootApplication 
@MapperScan("com.zzg.mapper") 
public class Application { 
 
	public static void main(String[] args) { 
		// TODO Auto-generated method stub 
		SpringApplication.run(Application.class, args); 
	} 
 
} 

第七步:编辑SpringSecurity 用户权限系统 核心代码: 

1、自定义UserDetails

springsecurity 用户信息必须实现org.springframework.security.core.userdetails.UserDetails 接口

package com.zzg.security.user; 
 
import java.util.ArrayList; 
import java.util.Collection; 
import java.util.List; 
import org.springframework.security.core.GrantedAuthority; 
import org.springframework.security.core.authority.SimpleGrantedAuthority; 
import org.springframework.security.core.userdetails.UserDetails; 
import com.zzg.entity.Permission; 
import com.zzg.entity.Role; 
 
public class AuthUserDetails implements UserDetails { 
	 
	 
    /**    
	 * @Fields serialVersionUID : TODO(用一句话描述这个变量表示什么)    
	 */    
	private static final long serialVersionUID = 1L; 
	private String nickname; 
    private String pswd; 
     
    // 相关角色 
    private List<Role> roles; 
    // 相关权限 
    private List<Permission> permission; 
     
    // set 和  get 方法 
	public String getNickname() { 
		return nickname; 
	} 
 
	public void setNickname(String nickname) { 
		this.nickname = nickname; 
	} 
 
	public String getPswd() { 
		return pswd; 
	} 
 
	public void setPswd(String pswd) { 
		this.pswd = pswd; 
	} 
 
	public List<Role> getRoles() { 
		return roles; 
	} 
 
	public void setRoles(List<Role> roles) { 
		this.roles = roles; 
	} 
 
	public List<Permission> getPermission() { 
		return permission; 
	} 
 
	public void setPermission(List<Permission> permission) { 
		this.permission = permission; 
	} 
	 
	// 构造函数 
	public AuthUserDetails(String nickname, String pswd, List<Role> roles, List<Permission> permission) { 
		super(); 
		this.nickname = nickname; 
		this.pswd = pswd; 
		this.roles = roles; 
		this.permission = permission; 
	} 
	 
 
	// 用户关联角色权限设置 
	@Override 
	public Collection<? extends GrantedAuthority> getAuthorities() { 
		// TODO Auto-generated method stub 
		 List<GrantedAuthority> auths = new ArrayList<>(); 
		 List<Role> roles = this.getRoles(); 
		 for (Role role : roles) { 
	            auths.add(new SimpleGrantedAuthority(role.getName())); 
	        } 
		  
		return auths; 
	} 
 
	// 用户密码设置 
	@Override 
	public String getPassword() { 
		// TODO Auto-generated method stub 
		return this.pswd; 
	} 
	// 用户用户名设置 
	@Override 
	public String getUsername() { 
		// TODO Auto-generated method stub 
		return this.nickname; 
	} 
 
	@Override 
	public boolean isAccountNonExpired() { 
		// TODO Auto-generated method stub 
		return true; 
	} 
 
	@Override 
	public boolean isAccountNonLocked() { 
		// TODO Auto-generated method stub 
		return true; 
	} 
 
	@Override 
	public boolean isCredentialsNonExpired() { 
		// TODO Auto-generated method stub 
		return true; 
	} 
 
	@Override 
	public boolean isEnabled() { 
		// TODO Auto-generated method stub 
		return true; 
	} 
 
} 

2、自定义UserDetailsService

springsecurity 的用户鉴权信息时通过org.springframework.security.core.userdetails.UserDetailsService的loadUserByUsername方法实现的

package com.zzg.security.user; 
 
import java.util.List; 
import java.util.stream.Collectors; 
 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.security.core.userdetails.UserDetails; 
import org.springframework.security.core.userdetails.UserDetailsService; 
import org.springframework.security.core.userdetails.UsernameNotFoundException; 
 
import com.zzg.entity.Permission; 
import com.zzg.entity.Role; 
import com.zzg.entity.RolePermission; 
import com.zzg.entity.User; 
import com.zzg.entity.UserRole; 
import com.zzg.service.PermissionService; 
import com.zzg.service.RolePermissionService; 
import com.zzg.service.RoleService; 
import com.zzg.service.UserRoleService; 
import com.zzg.service.UserService; 
 
public class CustomerUserService implements UserDetailsService { 
	@Autowired 
	private UserService userService; 
	@Autowired 
	private PermissionService permissionService; 
	@Autowired 
	private UserRoleService userRoleService; 
	@Autowired 
	private RoleService roleService; 
	@Autowired 
	private RolePermissionService rolePermissionService; 
 
	 
	@Override 
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { 
		// TODO Auto-generated method stub 
		User user = userService.getByUserName(username); 
		if (user == null) { 
	            throw new UsernameNotFoundException("用户名不存在"); 
	    } 
		// 用户涉及角色 
		List<UserRole> userRoles = userRoleService.getByUid(user.getId()); 
		List<Long> list = userRoles.stream().map(UserRole::getRid).collect(Collectors.toList()); 
		List<Role> roles = roleService.getByIds(list); 
		 
  
		// 用户涉及权限 
		List<Long> roleIds = roles.stream().map(Role::getId).collect(Collectors.toList()); 
		List<RolePermission> rolePermissions = rolePermissionService.getByRoleIds(roleIds); 
  
		List<Long> permissionIds = rolePermissions.stream().map(RolePermission::getPid).collect(Collectors.toList()); 
		List<Permission> permissions = permissionService.getByPermissionIds(permissionIds); 
 
		//返回用户详情数据信息 
		AuthUserDetails authUserDetails = new AuthUserDetails(user.getNickname(),user.getPswd(),roles,permissions); 
		return authUserDetails; 
	} 
 
} 

3、springsecurity 配置类

通过javaconfig 的方式,创建springsecurity 的配置类。指定AuthenticationManager使用我们自己的UserDetailsService 来获取用户信息,并设置首页、登录页等相关信息

package com.zzg.security.config; 
 
import org.springframework.context.annotation.Bean; 
import org.springframework.context.annotation.Configuration; 
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; 
import org.springframework.security.config.annotation.web.builders.HttpSecurity; 
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 
import org.springframework.security.core.userdetails.UserDetailsService; 
import org.springframework.security.crypto.password.NoOpPasswordEncoder; 
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler; 
import com.zzg.security.user.CustomerUserService; 
 
@Configuration 
@EnableWebSecurity 
@EnableGlobalMethodSecurity(prePostEnabled = true)  //  启用方法级别的权限认证 
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { 
	@Bean 
	UserDetailsService customUserService() { 
		return new CustomerUserService(); 
	} 
 
	@Override 
	protected void configure(AuthenticationManagerBuilder auth) throws Exception { 
		// 设置密码为明文 
		auth.userDetailsService(customUserService()).passwordEncoder(NoOpPasswordEncoder.getInstance()); 
	} 
 
	@Override 
	protected void configure(HttpSecurity http) throws Exception { 
	//  允许所有用户访问"/"和"/index.html" 
		         http.authorizeRequests() 
		                 .antMatchers("/", "/index.html").permitAll() 
		                 .anyRequest().authenticated()   // 其他地址的访问均需验证权限 
		                 .and() 
		                 .formLogin() 
		                 .loginPage("/login.html")   //  登录页 
		                 //.successForwardUrl("/index") // 登入成功后,跳转至指定页面 
		                 .defaultSuccessUrl("/index")   // 访问指定页面,用户未登入,跳转至登入页面,如果登入成功,跳转至用户访问指定页面,用户访问登入页面,默认的跳转页面 
		                 .failureUrl("/login-error.html").permitAll() 
		                 .and() 
		                 .logout() 
		                 .logoutSuccessUrl("/index.html");  
	} 
 
} 

温馨提示:springsecurity 用户验证成功,无法跳转至系统默认页面,且浏览器提示404 的错误。配置MVC视图解析器。

自定义MVC实体解析器需要集成org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter类。

package com.zzg.mvc.config; 
 
import org.springframework.context.annotation.Configuration; 
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; 
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 
 
@Configuration 
public class WebMvcConfig extends WebMvcConfigurerAdapter { 
 
	@Override 
	public void addViewControllers(ViewControllerRegistry registry) { 
		// TODO Auto-generated method stub 
		registry.addViewController("/login").setViewName("login"); 
	} 
	 
 
} 

第八步:spirngsecurity 用户登入和相关业务代码

package com.zzg.controller; 
 
import org.springframework.stereotype.Controller; 
import org.springframework.ui.Model; 
import org.springframework.web.bind.annotation.RequestMapping; 
 
@Controller 
public class LoginController { 
	// Login form 
	@RequestMapping("/login.html") 
	public String login() { 
		return "login"; 
	} 
 
	@RequestMapping("/index") 
	public String index() { 
		return "index"; 
	} 
 
	// Login form with error 
	@RequestMapping("/login-error.html") 
	public String loginError(Model model) { 
		model.addAttribute("loginError", true); 
		return "login"; 
	} 
 
} 
package com.zzg.controller; 
 
import org.springframework.security.access.annotation.Secured; 
import org.springframework.security.access.prepost.PreAuthorize; 
import org.springframework.stereotype.Controller; 
import org.springframework.web.bind.annotation.RequestMapping; 
 
@Controller 
@RequestMapping("/userInfo") 
public class UserInfoController { 
	/** 
     * 用户查询. 
     * @return 
     */ 
    @RequestMapping("/userList") 
    @Secured({"admin","user"})   
    public String userInfo(){ 
        return "userInfo"; 
    } 
  
    /** 
     * 用户添加; 
     * @return 
     */ 
    @RequestMapping("/userAdd") 
    @Secured({"admin","user"})   
    public String userInfoAdd(){ 
        return "userInfoAdd"; 
    } 
  
    /** 
     * 用户删除; 
     * @return 
     */ 
    @RequestMapping("/userDel") 
    @Secured({"admin"})   
    public String userDel(){ 
        return "userInfoDel"; 
    } 
} 

boot-srcurity-controller 项目截图:

声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

发表评论
搜索
KIKK导航

KIKK导航

排行榜
关注我们

一个IT知识分享的公众号