Spring Security概述
1.什么是Spring Security?
Spring Security是一个Java框架,用于保护应用程序的安全性。它提供了一套全面的安全解决方案,包括身份验证、授权、防止攻击等功能。Spring Security基于过滤器链的概念,可以轻松地集成到任何基于Spring的应用程序中。它支持多种身份验证选项和授权策略,开发人员可以根据需要选择适合的方式。此外,Spring Security还提供了一些附加功能,如集成第三方身份验证提供商和单点登录,以及会话管理和密码编码等。总之,Spring Security是一个强大且易于使用的框架,可以帮助开发人员提高应用程序的安全性和可靠性。
什么是授权
这个根据用户的权限来控制用户使用资源的过程就是授权。
为什么要授权
认证是为了保护用户身份的合法性,授权则是为了更细的粒度的对隐私数据经行划分,授权是在认证通过后发生的,控制不同的用户能够访问不同的资源;
授权:授权是用户认证通过根据用户的权限来控制用户访问资源的过程,拥有资源的访问权限则正常访问,没有权限则拒绝访问;
Spring Security入门体验
一.快速搭建Spring Security安全框架项目;
1.1--创建一个SpringBoot项目;
1.2--修改SpringBoot的版本号,并修改jdk版本号;
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>SpringSecurity001</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>SpringSecurity001</name>
<description>SpringSecurity001</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.6.13</spring-boot.version>
<!--SpringBoot版本号 这里使用的JDK版本为8-->
</properties>
<dependencies>
<!--引入Spring Security安全框架依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--添加lombok依赖 实体类的get set方法生成-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--测试依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<configuration>
<mainClass>com.aaa.SpringSecurity001Application</mainClass>
<skip>true</skip>
</configuration>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
1.3--引入SPringleSecurity依赖;
<!--引入Spring Security安全框架依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
1.4--创建一个HelloController,Controller层定义一个资源;
1.5--启动项目并访问资源路径;
访问路径:http://localhost:8080/hello
注:我们发现使用了security后在访问我们自己的接口,security会拦截并跳转到认证页面,认证后才可以访问。默认认证的账号uer密码在控制台;
二.创建Spring Security自定义账户和密码;
我们刚才使用的是security自带的账户和密码,我们自己也可以自定义账户和密码;
2.1--在application.properties配置文件中定义一个账户和密码;
自定义账户和密码文件如下:
#创建Spring Security自定义账户和密码
#账户
spring.security.user.name=admin
#密码
spring.security.user.password=123456
server.port=8080
注:配置完自定义文件和密码,重启运行,这是控制台中没有密码(控制台不会生成密码);
注:这种方式只能定义一个账户和密码,无法定义多个账户和密码;
三.自定义多个账户和密码
在配置文件中,只能定义一个账户和密码。我们可以定义一个配置类,完成多个账号和密码的定义;
1.创建Config层 MysecurityConfig;
配置类内容
package com.aaa.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication() //基于内存创建的账户和密码 未来可以用来连接数据库
//账户
.withUser("zhangsan")
//密码
.password("123456")
//用户具备的角色
.roles("admin")
.and() //连接符
.withUser("lisi")
.password("012345")
.roles("test")
.and()
.withUser("wangwu")
.password("567890")
.roles("group");
}
}
注:如果使用了配置类,那么之前在配置文件中定义的账户和密码不在生效;
控制台错误提示:需要给它指定的加密器;
解决方式:添加加密器
//可以把该方法返回的对象交于Spring容器管理
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
package com.aaa.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.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
//可以把该方法返回的对象交于Spring容器管理
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication() //基于内存创建的账户和密码 未来可以用来连接数据库
//账户
.withUser("zhangsan")
//密码
.password(passwordEncoder().encode("123456"))
//用户具备的角色
.roles("admin")
.and() //连接符
.withUser("lisi")
.password(passwordEncoder().encode("012345"))
.roles("test")
.and()
.withUser("wangwu")
.password(passwordEncoder().encode("567890"))
.roles("group");
}
}
注:把明文密码通过加密器经行加密;
再次访问资源
四.密码加密器
密码加密器,可以把把明文转换为密文 encode
同时也可以匹配密码 matches;
package com.aaa.Test;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
public class test {
public static void main(String[] args) {
//创建加密器对象
PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
//使用加密器
String encode = passwordEncoder.encode("123456");
System.out.println(encode);
//匹配密码 第一个参数是客户输得密码 第二个参数是加密器密文
//把客户输得密码和加密过的密码经行比对是否一致,一致返回true,不一致返回flase;
boolean matches = passwordEncoder.matches("123456", encode);
//结果为true
System.out.println(matches);
}
}
问题:对称加密和非对称加密
答:对称加密:加密和解密使用的密钥是同一个; --这种加密的方式可以破解
非对称加密: 加密和解密使用的密钥不是同一个;--这种加密的方式无法破解
五.获取当前用户的信息
获取登录成功者的信息
package com.aaa.Controller;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello(){
return "hello资源·······";
}
@GetMapping("/info")
public Authentication info(){
//把当前信息保存到SecurityContext类中;
SecurityContext securityContext = SecurityContextHolder.getContext();
//把当前用户封装到Authentication类中 账户 密码 权限 角色等信息
Authentication authentication = securityContext.getAuthentication();
return authentication;
}
}
Security框架会把当前用户信息封装到Authentication中,并把该类对象存放到SecurityContext中;
访问资源路径http://localhost:8080/info
六.修改它的登录页面
默认security提供了一个登录页面,如果不想使用它提供的页面,我们可以指定我们自己的登录页面;
1.自己在static静态资源文件下创建一个登录页面;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录页</title>
<style>
body {
background-color: #222;
font-family: Arial, sans-serif;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
}
.login-container {
background-color: #333;
padding: 40px;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
}
h1 {
text-align: center;
}
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
margin-bottom: 5px;
}
.form-group input[type="text"],
.form-group input[type="password"] {
width: 100%;
padding: 10px;
border-radius: 5px;
border: none;
background-color: #555;
color: #fff;
}
.form-group input[type="submit"] {
width: 100%;
padding: 10px;
border-radius: 5px;
border: none;
background-color: #007bff;
color: #fff;
cursor: pointer;
transition: background-color 0.3s ease;
}
.form-group input[type="submit"]:hover {
background-color: #0056b3;
}
</style>
</head>
<body>
<div class="login-container">
<h1>Welcome to Cool Login Page</h1>
<form action="login" method="post">
<div class="form-group">
<label for="username">Username:</label>
<!--账户-->
<input type="text" id="username" name="username" required>
</div>
<div class="form-group">
<label for="password">Password:</label>
<!--密码-->
<input type="password" id="password" name="password" required>
</div>
<div class="form-group">
<input type="submit" value="Login">
</div>
</form>
</div>
</body>
</html>
2.修改security配置类;在config层 HelloConfig文件中重写configure方法;
@Override
protected void configure(HttpSecurity http) throws Exception {
//设置表单登录信息
http.formLogin()
//设置自己的登录页面
.loginPage("/login.html")
//设置登录表单的提交路径 要和login.html中的action一致
.loginProcessingUrl("/login")
//这个页面允许放行
.permitAll();
//禁止跨域伪造请求验证
http.csrf().disable();
//其他请求路径都要认证
http.authorizeRequests().anyRequest().authenticated();
}
访问路径访问info或者hello都可以进入到自己的登录页面;
七.设置跳转登录成功页面
默认登录成功 / 或原来的访问路径
创建SuccessController
package com.aaa.Controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
@Controller
public class SuccessController {
@PostMapping("/success")
public String success(){
return "redirect:/success.html";
}
}
创建一个success.html登录成功页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>登录成功</h1>
</body>
</html>
输入账号和密码
登录成功
授权的实现
授权:用户具有的权限和资源绑定的过程就是授权;
第一步:修改config MySecurityConfig配置文件
第二步:创建自定义资源访问 controller层 AuthController资源文件
package com.aaa.Controller;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
//资源
@RestController
public class AuthController {
@GetMapping("select")
public String select(){
System.out.println("查询资源");
return "查询资源";
}
@GetMapping("update")
public String update(){
System.out.println("修改资源");
return "修改资源";
}
@GetMapping("delete")
public String delete(){
System.out.println("删除资源");
return "删除资源";
}
@GetMapping("xxx")
public String xxx(){
System.out.println("共享资源");
return "共享资源";
}
}
第三步: 权限和资源进行绑定 config MySecurityConfig配置文件
package com.aaa.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.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
//可以把该方法返回的对象交于Spring容器管理
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
//设置表单登录信息
http.formLogin()
//设置自己的登录页面
.loginPage("/login.html")
//设置登录表单的提交路径 要和login.html中的action一致
.loginProcessingUrl("/login")
//表示登录成功跳转路径 提交方式必须为post请求
.successForwardUrl("/success")
//这个页面允许放行
.permitAll();
//设定资源和权限进行绑定
http.authorizeRequests()
.antMatchers("/select").hasAnyAuthority("user:select")
.antMatchers("/update").hasAnyAuthority("user:update")
.antMatchers("/delect").hasAnyAuthority("user:delect")
.antMatchers("/xxx").hasAnyAuthority("user:xxx");
//异常处理页面
http.exceptionHandling().accessDeniedPage("/403.html");
//禁止跨域伪造请求验证
http.csrf().disable();
//其他请求路径都要认证
http.authorizeRequests().anyRequest().authenticated();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication() //基于内存创建的账户和密码 未来可以用来连接数据库
//账户
.withUser("zhangsan")
//密码
.password(passwordEncoder().encode("123456"))
//用户具备的角色
.roles("admin")
//设定用户权限
.authorities("user:select","user:update","user:delete")
.and() //连接符
.withUser("lisi")
.password(passwordEncoder().encode("012345"))
.roles("test")
.authorities("user:xxx")
.and()
.withUser("wangwu")
.password(passwordEncoder().encode("567890"))
.roles("group");
}
}
第四步:访问资源
上面再访问没有的权限资源时,出现上面的错误界面,这种界面对客户友好。跳转到一个权限不足的界面;
使用security注解完成授权
(思考: 上面权限和资源得到绑定 需要手动一一绑定。真正再开发中我们具有的权限和资源是非常多的。如果手动一一绑定是很麻烦的。)
第一步:开启security权限注解驱动
第二步:再相应的资源上使用注解
controller层 AuthController资源文件
package com.aaa.Controller;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
//资源
@RestController
public class AuthController {
@GetMapping("select")
@PreAuthorize(value = "hasAuthority('user:select')")
public String select(){
System.out.println("查询资源");
return "查询资源";
}
@GetMapping("update")
@PreAuthorize(value = "hasAuthority('user:upate')")
public String update(){
System.out.println("修改资源");
return "修改资源";
}
@GetMapping("delete")
@PreAuthorize(value = "hasAuthority('user:delete')")
public String delete(){
System.out.println("删除资源");
return "删除资源";
}
@GetMapping("xxx")
@PreAuthorize(value = "hasAuthority('user:xxx')")
public String xxx(){
System.out.println("共享资源");
return "共享资源";
}
}
第三步:修改security配置
第四步:访问资源,流程是一样的 略
了解security认证的流程(源码)
核心过滤器:UsernamePasswordAuthenticationFilter
使用Spring Security连接数据库(自定义认证--需要连接数据库)
第一步:创建securtiy数据库
DROP TABLE IF EXISTS `sys_permission`;
CREATE TABLE `sys_permission` (
`perid` int(0) NOT NULL AUTO_INCREMENT,
`pername` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
`percode` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`perid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of sys_permission
-- ----------------------------
INSERT INTO `sys_permission` VALUES (1, '用户查询', 'user:query');
INSERT INTO `sys_permission` VALUES (2, '用户添加', 'user:add');
INSERT INTO `sys_permission` VALUES (3, '用户修改', 'user:update');
INSERT INTO `sys_permission` VALUES (4, '用户删除', 'user:delete');
INSERT INTO `sys_permission` VALUES (5, '用户导出', 'user:export');
-- ----------------------------
-- Table structure for sys_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role` (
`roleid` int(0) NOT NULL AUTO_INCREMENT,
`rolename` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`roleid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of sys_role
-- ----------------------------
INSERT INTO `sys_role` VALUES (1, '管理员');
INSERT INTO `sys_role` VALUES (2, '测试人员');
INSERT INTO `sys_role` VALUES (3, '普通用户');
-- ----------------------------
-- Table structure for sys_role_permission
-- ----------------------------
DROP TABLE IF EXISTS `sys_role_permission`;
CREATE TABLE `sys_role_permission` (
`perid` int(0) NULL DEFAULT NULL,
`roleid` int(0) NULL DEFAULT NULL
) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of sys_role_permission
-- ----------------------------
INSERT INTO `sys_role_permission` VALUES (2, 1);
INSERT INTO `sys_role_permission` VALUES (1, 1);
INSERT INTO `sys_role_permission` VALUES (3, 1);
INSERT INTO `sys_role_permission` VALUES (4, 1);
INSERT INTO `sys_role_permission` VALUES (2, 2);
INSERT INTO `sys_role_permission` VALUES (1, 2);
INSERT INTO `sys_role_permission` VALUES (3, 2);
INSERT INTO `sys_role_permission` VALUES (1, 3);
INSERT INTO `sys_role_permission` VALUES (5, 3);
-- ----------------------------
-- Table structure for sys_user
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
`userid` int(0) NOT NULL AUTO_INCREMENT,
`username` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
`userpwd` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
`sex` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
`address` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`userid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of sys_user
-- ----------------------------
INSERT INTO `sys_user` VALUES (1, '张三', '$2a$10$cI7e7bgSs9.9nNHhxKO9LuK/Ll.AeZwgUyZb77oD2y3UwwZyZhWG6', '男', '郑州');
INSERT INTO `sys_user` VALUES (2, '李四', '$2a$10$cI7e7bgSs9.9nNHhxKO9LuK/Ll.AeZwgUyZb77oD2y3UwwZyZhWG6', '男', '北京');
INSERT INTO `sys_user` VALUES (3, '王五', '$2a$10$cI7e7bgSs9.9nNHhxKO9LuK/Ll.AeZwgUyZb77oD2y3UwwZyZhWG6', '女', '杭州');
-- ----------------------------
-- Table structure for sys_user_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_user_role`;
CREATE TABLE `sys_user_role` (
`userid` int(0) NOT NULL,
`roleid` int(0) NULL DEFAULT NULL
) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of sys_user_role
-- ----------------------------
INSERT INTO `sys_user_role` VALUES (1, 1);
INSERT INTO `sys_user_role` VALUES (2, 2);
INSERT INTO `sys_user_role` VALUES (3, 3);
INSERT INTO `sys_user_role` VALUES (1, 2);
SET FOREIGN_KEY_CHECKS = 1;
第二步:创建一个SpringBoot项目--------引入相关的依赖(lombok依赖 mysql驱动依赖 mybatis-plus依赖,security启动依赖)
<dependencies>
<!--加入security安全框架依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!--lombok依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--mysql驱动依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--mybatis-plus依赖-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
第三步:创建实体类 entity层 (User Role Permission)
User实体类
package com.aaa.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("sys_user") //实体类和数据库表名不一致时,使用该注解进行映射
public class User {
@TableId(type = IdType.AUTO) //主键自增
private Integer userid;
private String username;
private String userpwd;
private String sex;
private String address;
}
Role实体类
package com.aaa.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("sys_role") //实体类和数据库表名不一致时,使用该注解进行映射
public class Role {
@TableId(type = IdType.AUTO) //主键自增
private Integer roleid;
private String rolename;
}
Permission实体类
package com.aaa.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("sys_permission") //实体类和数据库表名不一致时,使用该注解进行映射
public class Permission {
@TableId(type = IdType.AUTO) //主键自增
private Integer perid;
private String pername;
private String percode;
}
第四步:创建相应的Dao接口 Dao层 (UserDao RoleDao PermissionDao)
UserDao接口
package com.aaa.dao;
import com.aaa.entity.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface UserDao extends BaseMapper<User> {
}
ReloDao接口
package com.aaa.dao;
import com.aaa.entity.Role;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface RoleDao extends BaseMapper<Role> {
}
PermissionDao接口
package com.aaa.dao;
import com.aaa.entity.Permission;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
public interface PermissionDao extends BaseMapper<Permission> {
//查找用户的权限
@Select("select distinct p.* from sys_user_role u join sys_role_permission r on u.roleid=r.roleid join sys_permission p on r.perid=p.perid where userid=#{userId}")
public List<Permission> selectByUserId(Integer userId);
}
第五步:创建业务层 Service MyUserDetailService代码
package com.aaa.service;
import com.aaa.dao.PermissionDao;
import com.aaa.dao.UserDao;
import com.aaa.entity.Permission;
import com.aaa.entity.User;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@Service
public class MyUserDetailService implements UserDetailsService {
@Autowired
private UserDao userDao;
@Autowired
private PermissionDao permissionDao;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//1. 根据账户查找用户信息
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("username",username);
User user = userDao.selectOne(queryWrapper);
//2.判断用户是否为null
if(user!=null){
//3.查找用户的具体权限
List<Permission> permissions = permissionDao.selectByUserId(user.getUserid());
/**
* String username, 账户
* String password, 密码-->而是数据库中存在的密码
* Collection<? extends GrantedAuthority> authorities 当前用户具有的权限
*/
Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
//把List<Permission>转化为Collection<SimpleGrantedAuthority>
for(Permission per:permissions){
SimpleGrantedAuthority simpleGrantedAuthority=new SimpleGrantedAuthority(per.getPercode());
authorities.add(simpleGrantedAuthority);
}
org.springframework.security.core.userdetails.User userDetail=new org.springframework.security.core.userdetails.User(user.getUsername(),user.getUserpwd(),authorities);
return userDetail;
}
return null;
}
}
第六步:创建Security配置文件 config层 mySecurityConfig文件
package com.aaa.config;
import com.aaa.service.MyUserDetailService;
import org.springframework.beans.factory.annotation.Autowired;
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.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private MyUserDetailService userDetailService;
//添加加密器
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//使用数据库账号和密码
auth.userDetailsService(userDetailService);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
//设置表单信息
//使用自己的前端登录页面
http.formLogin().loginPage("/login.html")
.loginProcessingUrl("/login")
.successForwardUrl("/success")
.permitAll();
//异常处理页面
http.exceptionHandling().accessDeniedPage("/403.html");
//禁用跨域伪造响应
http.csrf().disable();
//其他所有路径通过都需要认证
http.authorizeRequests().anyRequest().authenticated();
}
}
第七步:配置application.properties文件,连接数据库
server.port=8080
spring.datasource.url=jdbc:mysql://localhost:3306/security
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=root
第八步:在SpringSecurity002Application 启动类中添加注解让其扫描到com.aaa.dao层
package com;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
//添加注解 包扫描到dao层
@MapperScan(basePackages = "com.aaa.dao")
public class SpringSecurity002Application {
public static void main(String[] args) {
SpringApplication.run(SpringSecurity002Application.class, args);
}
}
第九步:访问资源