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

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

基于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', 'admin@163.com', '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 项目截图:

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值