SpringSecurity
官方文档
https://spring.io/projects/spring-security
一. SpringSecurity 简介
Spring Security是一个功能强大且高度可定制的身份验证和访问控制框架。它实际上是保护基于spring的应用程序的标准。
Spring Security是一个框架,侧重于为Java应用程序提供身份验证和授权。与所有Spring项目一样,Spring安全性的真正强大之处在于它可以轻松地扩展以满足定制需求
spring security 的核心功能主要包括:
- 认证 (你是谁)
- 授权 (你能干什么)
- 攻击防护 (防止伪造身份)
二.SpringSecurity 案例
1. 创建一个springboot 项目 (没有加入SpringSecurity的包)
写一个controller类
@RestController public class TestController { @GetMapping("/hello") public String hello(){ return "hello !"; } } |
测试发现:
当我们在浏览器访问http://localhost:8080/hello的时候可以在浏览器看到hello!
2. 项目中导入SpringSecurity的依赖
<!-- 父依赖 --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.4.RELEASE</version> <relativePath/> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <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> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-test</artifactId> <scope>test</scope> </dependency> </dependencies> |
再次访问http://localhost:8080/hello 发现 会自动跳转到Spring Security 自带的一个登录页面
说明Spring Security 已经起作用了,我们需要登陆才能访问。
右键点击查看源代码:
|
上面的html中有个form ,其中action="/login",这个/login依然是spring security提供的。form表单提交了三个数据:
username 用户名
password 密码
_csrf CSRF保护方面的内容,暂时先不展开解释 CSRF 跨站请求伪造
3. 用户名配置
默认情况下,登录的用户名是 user,密码则是项目启动时随机生成的字符串,可以从启动的控制台日志中看到默认密码:
我们在登录页面输入user和密码8fa79a36-8701-4419-826f-cb21a1fa9dd5。可以登录成功,并能访问/hello的内容。
这个随机生成的密码,每次启动时都会变。对登录的用户名/密码进行配置,有三种不同的方式:
- 在 application.yml 中进行配置
- 通过 Java 代码配置在内存中
- 通过 Java 从数据库中加载
配置文件配置用户名/密码
|
4. 自定义security配置
上面我们看到默认情况下,spring为我们提供了一个「httpBasic」模式的简单登陆页面,并在控制台输出了密码(这个密码每次启动都是不一样的)。如果我们想用自己的定义的账号密码,则需要改配置。也就是在 Java 代码中配置用户名密码 。
如下:
新建一个class :MySecurityConfig
|
记住几个类:
WebSecurityConfigurerAdapter:自定义Security策略
AuthenticationManagerBuilder:自定义认证策略
@EnableWebSecurity:开启WebSecurity模式
Spring Security的两个主要目标是 “认证”(Authentication) 和 “授权”(Authorization)(访问控制)。
测试,我们可以使用这些账号登录进行测试!发现会报错!
There is no PasswordEncoder mapped for the id “null”
原因,我们要将前端传过来的密码进行某种方式加密,否则就无法登录
|
5. 角色 访问 资源
|
如果登录的时候是用 admin 登录 发现是都可以访问的,因为它有 root和hjj 这两个权限
但如果是用cw , 他只有root 的权限 只能访问 /user/** 下面的,不能访问 /product/** 下面的
同理 可知 用 yyqx 登录的,他只有 hjj 的权限,所以不能访问 /user/** 下面的
7. 自定义登录页面
7.1导入依赖
|
7.2 写页面
1. 导入命名空间
xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5"
2. 写首页
index.html
|
login.html
|
3. 定制请求的授权规则
修改代码
|
还可以开启记住我 功能
页面:
<div >
<input type="checkbox" name="remember"/> 记住我
</div >
后端:
//定制记住我的参数!
http.rememberMe().rememberMeParameter("remember");
三.SpringSecurity 案例2(数据库)
1.数据库
CREATE DATABASE /*!32312 IF NOT EXISTS*/`mybatis-role` /*!40100 DEFAULT CHARACTER SET utf8 */; USE `mybatis-role`; /*Table structure for table `t_role` */ DROP TABLE IF EXISTS `t_role`; CREATE TABLE `t_role` ( `role_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '角色ID', `role_name` varchar(18) DEFAULT NULL COMMENT '角色名', PRIMARY KEY (`role_id`) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8; /*Data for the table `t_role` */ insert into `t_role`(`role_id`,`role_name`) values (1,'admin'),(2,'root'),(3,'you'),(4,'屈原'); /*Table structure for table `t_user` */ DROP TABLE IF EXISTS `t_user`; CREATE TABLE `t_user` ( `user_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户ID', `login_name` varchar(30) DEFAULT NULL COMMENT '用户名', `login_pass` varchar(65) DEFAULT NULL COMMENT '密码', PRIMARY KEY (`user_id`) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8; insert into `t_user`(`user_id`,`login_name`,`login_pass`) values (1,'hjj','$2a$10$Mx24DvBBzoMC4gfHeuADx.wyK1G3PMYtWhFAH89Gjp6XjlbTeg0XC'),(2,'cw','$2a$10$Mx24DvBBzoMC4gfHeuADx.wyK1G3PMYtWhFAH89Gjp6XjlbTeg0XC'),(3,'yyqx','$2a$10$Mx24DvBBzoMC4gfHeuADx.wyK1G3PMYtWhFAH89Gjp6XjlbTeg0XC'),(4,'hhh','$2a$10$4o9XO2TB4QJzDJcP3J9vI.nApUZRD.sLXBDZzmbKQoNO6jqZdmAaS'); DROP TABLE IF EXISTS `t_user_role`; CREATE TABLE `t_user_role` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID', `user_id` int(11) NOT NULL COMMENT '用户ID', `role_id` int(11) NOT NULL COMMENT '角色ID', PRIMARY KEY (`id`), KEY `user_id` (`user_id`), KEY `role_id` (`role_id`), CONSTRAINT `role_id` FOREIGN KEY (`role_id`) REFERENCES `t_role` (`role_id`), CONSTRAINT `user_id` FOREIGN KEY (`user_id`) REFERENCES `t_user` (`user_id`) ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8; /*Data for the table `t_user_role` */ insert into `t_user_role`(`id`,`user_id`,`role_id`) values (1,1,1),(2,1,2),(3,2,2),(4,3,3),(5,4,4),(6,3,2),(7,3,1),(8,4,2); |
2. 新建项目
2.1 导入相关的依赖
|
2.2 配置application.yml
修改你自己的数据库名,用户名和密码
你的实体类的全类名
|
2.3写启动类
启动类上加
@MapperScan("com.example.springsecurity002.mapper")
扫描你自己接口的包
2.4 用mybatis-plus 生成代码
|
3. 写业务逻辑
3.1. UserMapper
|
3.2. UserService 和 UserServiceImpl
|
3.3UserMapper.xml
|
3.4 在实体类加上 属性
@ApiModelProperty(value = "用户拥有的权限列表")
List<Role> roleList ;
3.5 自定义UserDetailsService
spring security在认证过程中需要查找用户,会调用UserDetailsService的loadUserByUsername方法得到一个UserDetails
|
org.springframework.security.core.authority.AuthorityUtils.createAuthorityList(String...)
工具方法获取创建 SimpleGrantedAuthority 对象添加角色时需要手动在角色名称前
加“ROLE_”前缀。
3.6 写SpringSecurity 的配置类
|
3.6 写页面
登录页面
login.html
<form name="form" th:action="@{/login}" action="/login" method="POST">
<div>
<label>账号</label>
<input type="text" name="username" value="" placeholder="请输入用户名" />
</div>
<div>
<label>密码</label>
<input type="password" name="password" placeholder="请输入密码" />
</div>
<input type="submit" id="login" value="Login"/>
</form>
首页
home.html
<div>
<!--如果未登录-->
<div sec:authorize="!isAuthenticated()">
<a class="item" th:href="@{/login}">
<i class="address card icon"></i> 登录
</a>
</div>
<!--如果已登录-->
<div sec:authorize="isAuthenticated()">
<a class="item">
<i class="address card icon"></i>
用户名:<span sec:authentication="principal.username"></span>
角色:<span sec:authentication="principal.authorities"></span>
</a>
</div>
<form th:action="@{/logout}" method="post">
<input type="submit" class="btn btn-primary" value="注销"/>
</form></div>
3.7 配置要跳转的路径
|