在Web开发中,安全第一位!!!安全虽属于应用的非功能性需求,但应当在应用开发系统设计之初就考虑进来,若开发后期才考虑安全的问题:
Web 应用的安全性包括 :
java 众所周知的安全权限管理框架:Shiro 和 Spring Security
Spring Security是一个java 安全框架,一个功能强大且高度可定制的身份验证和访问控制框架,是针对 spring 项目的安全框架,也是 spring boot 底层安全模块默认的技术选型,可实现强大的 web 安全控制。
Spring Security 框架支持的主流的认证方式:HTTP基本认证、HTTP表单验证、HTTP摘要认证、OpenID和LDAP等。
Spring Security框架在用户授权方面,提供基于角色的访问控制和访问控制列表(Access Control List, ACL),可以对应用中的领域对象进行细粒度的控制。
1、新建一个初始的 spring boot 2.6.5 项目 web 模块,整合 thymeleaf 模块
<!-- 导入 thymeleaf模块-->
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-thymeleaf -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>2.6.5</version>
</dependency>
2、导入静态资源(需要的一些简单的前端测试页面) or 手写几个测试页面
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TjpaG6jh-1648471124300)(C:\Users\86159\AppData\Roaming\Typora\typora-user-images\image-20220328202331117.png)]
3、controller 跳转!
@Controller
public class RouterController {
@RequestMapping({"/","/index"})
public String index(){
return "index";
}
@RequestMapping("/toLogin")
public String toLogin(){
return "views/login";
}
@RequestMapping("/level1/{id}")
public String level1(@PathVariable("id") int id){
return "views/level1/" + id;
}
@RequestMapping("/level2/{id}")
public String level2(@PathVariable("id") int id){
return "views/level2/" + id;
}
@RequestMapping("/level3/{id}")
public String level3(@PathVariable("id") int id){
return "views/level3/" + id;
}
}
4、测试实验环境是否OK!
环境搭建好之后,对于spring boot项目的安全控制,只需要引入 spring-boot-starter-security 模块,进行少量的配置,即可实现强大的安全管理!!
记住几个类:
Spring Security 的两个主要目标是"认证"和"授权"(访问控制),这两个概念是通用的,不只是在 Spring Security 中存在
目前,我们的测试环境,是所有人都可以访问,为了应用安全访问控制,使用 Spring Security
1、引入 Spring Security 模块
<!--导入 Spring Security模块-->
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>2.6.5</version>
</dependency>
2、参考官网,编写 Spring Security 配置类 ,编写基础配置类 SecurityConfig,定制请求的授权规则
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
//首页所有人可以访问,功能页只有有对应权限的人才能访问
//请求授权的规则~
http.authorizeRequests().antMatchers("/").permitAll()
.antMatchers("/level1/**").hasRole("vip1")
.antMatchers("/level2/**").hasRole("vip2")
.antMatchers("/level2/**").hasRole("vip3");
}
}
到这一步,测试一下,除了首页,其它页面都无法进入,因为只有登录之后才有权限访问其他页面,目前还未配置登录的角色!
3、在configure(HttpSecurity http)方法中加入以下配置,开启自动配置的登录功能!
//没有权限默认会到登录页面 此时我没有自己配置登录页,该登录页面是框架内置的
http.formLogin();
到这一步,测试发现,没有权限时,会跳转到登录的页面!(该登录页面是 Spring Security 框架自带的)
4、查看刚才登录页的注释信息,我们可以定义认证规则,重写configure(AuthenticationManagerBuilder auth)方法
//AOP:
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//这些数据正常应该是从数据库中去取,这里用的是虚拟数据
auth.inMemoryAuthentication()
.withUser("xzh").password("123456").roles("vip2","vip3")
.and()
.withUser("root").password("123456").roles("vip1","vip2","vip3")
.and()
.withUser("guest").password("123456").roles("vip1");
}
}
5、测试,使用这些账号登录进行测试,但是会报错!
// 报错 java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"
原因,我们需要将前端传过来的密码进行某种方式的加密,否则就无法登录,修改代码!
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//认证, springboot 2.1.x 可直接使用 这里springboot 2.6.5
// 报错 java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"
//报错原因: 在 Spring Security 5.0+ 新增了很多的加密方法
// 要想我们的项目正常登录,需要修改一下configure中的代码,需将前端传过来的密码进行某种方式加密
//spring security 官方推荐的是使用bcrypt加密方式
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//这些数据正常应该是从数据库中去取,这里用的是虚拟数据
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("xzh").password(new BCryptPasswordEncoder().encode("123456")).roles("vip2","vip3")
.and()
.withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3")
.and()
.withUser("guest").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1");
}
}
6、测试,登录成功,并且每个角色只能访问自己认证下的规则,Surprised!
1、注销,在configure(HttpSecurity http)方法中加入以下配置,开启注销功能
http.csrf().disable();//这里如果注销失败,要关闭csrf功能,springboot 2.6.5版本 需要此步骤!!!
http.logout().logoutSuccessUrl("/");
2、登录注销页面权限控制,在首页 index.html 中对未登录,已登录首页页面显示数据的控制
<div class="right menu">
<div sec:authorize="!isAuthenticated()">
<a class="item" th:href="@{/toLogin}">
<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>
<div sec:authorize="isAuthenticated()">
<a class="item" th:href="@{/logout}">
<i class="address card icon">i> 注销
a>
div>
div>
1、记住我,在configure(HttpSecurity http)方法中加入以下配置,开启记住我功能
//开启记住我功能 本质就是一个 cookie,默认保存两周,自定义接收前端的参数
http.rememberMe().rememberMeParameter("remember");
2、首页定制,之前的登录页是框架自带的,这里在configure(HttpSecurity http)方法中加入以下配置,显示自定义登录页面
//定制登录页 loginPage("/toLogin")
// 这里底层框架默认 usernameParameter 为 username 所以可通过usernameParameter("user") 这样的方式自定义前端传来的参数 user,password同理
http.formLogin().loginPage("/toLogin").usernameParameter("user").passwordParameter("pwd").loginProcessingUrl("/login");
完结!!!撒花!!!★,°:.☆( ̄▽ ̄)/$:.°★ 。