springboot 学习 安全 Spring Security
Spring Security是一个功能强大且高度可定制的身份验证和访问控制框架。侧重于为Java应用程序提供身份验证和授权。与所有Spring项目一样,Spring安全性的真正强大之处在于它可以轻松地扩展以满足定制需求,它实际上是保护基于spring的应用程序的标准。
一般来说,Web 应用的安全性包括用户认证(Authentication)和用户授权(Authorization)两个部分。用户认证指的是验证某个用户是否为系统中的合法主体,也就是说用户能否访问该系统。用户认证一般要求用户提供用户名和密码。系统通过校验用户名和密码来完成认证过程。用户授权指的是验证某个用户是否有权限执行某个操作。在一个系统中,不同用户所具有的权限是不同的。比如对一个文件来说,有的用户只能进行读取,而有的用户可以进行修改。一般来说,系统会为不同的用户分配不同的角色,而每个角色则对应一系列的权限。
Spring Security的两个主要目标是 “认证” 和 “授权”(访问控制)。
“认证”(Authentication)
身份验证是关于验证您的凭据,如用户名/用户ID和密码,以验证您的身份。
身份验证通常通过用户名和密码完成,有时与身份验证因素结合使用。
“授权” (Authorization)
授权发生在系统成功验证您的身份后,最终会授予您访问资源(如信息,文件,数据库,资金,位置,几乎任何内容)的完全权限。
这个概念是通用的,而不是只在Spring Security 中存在。
spring sercurity的官方文档如下
https://docs.spring.io/spring-security/site/docs/5.3.0.RELEASE/reference/html5
需要引入安全的模块
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
引入的框架记住几个类:
-
WebSecurityConfigurerAdapter:自定义Security策略
-
AuthenticationManagerBuilder:自定义认证策略
-
@EnableWebSecurity:开启WebSecurity模式
首先需要编写一个java类,需要继承WebSecurityConfigurerAdapter,同时使用@EnableWebSecurity 开启安全模式
可以重写很多方法,如下,重写了关于http的安全的方法
authorizeRequests().antMatchers("/") 表示授权请求的路径,/表示首页,primitAll表示所有人都可以请求得到,
由于是个链式方法,所以在跟同样的方法,hasRole表示对应请求,需要什么角色才可以访问到
@EnableWebSecurity
public class mysecurrity extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// 定制请求的授权规则
// 首页所有人可以访问
http.authorizeRequests().antMatchers("/").permitAll()
.antMatchers("/level1/**").hasRole("vip1")
.antMatchers("/level2/**").hasRole("vip2")
.antMatchers("/level3/**").hasRole("vip3");
}
}
使用了这个之后发现,除了首页,其他三个level3都不能登录,页面显示报错,由于没有授权
这时候可以使用http.formLogin();方法,当没有权限时会自动会返回这个框架自带的登录页面,如下
http.formLogin();

上面定义了用户角色来授权资源,我们可以通过重写configure(AuthenticationManagerBuilder auth)方法,来增加认证的用户,如下:
由于当前没有连接数据库,所以直接将用户保存的内存中,在内存做了认证
//定义认证规则
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//在内存中定义,也可以在jdbc中去拿....
auth.inMemoryAuthentication()
.withUser("zhangzhang").password("123456").roles("vip2","vip3")
.and()
.withUser("root").password("123456").roles("vip1","vip2","vip3")
.and()
.withUser("guest").password("123456").roles("vip1","vip2");
}
配置上面这里页面会有一个500的报错,如下

报错原因时由于,输入密码需要进行加密,毕竟这是安全的框架嘛~
如下,多添加一个passwordEncoder()方法,new BCryptPasswordEncoder()这个表示加密的方式,方式有很多
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//在内存中定义,也可以在jdbc中去拿....
//Spring security 5.0中新增了多种加密方式,也改变了密码的格式。
//要想我们的项目还能够正常登陆,需要修改一下configure中的代码。我们要将前端传过来的密码进行某种方式加密
//spring security 官方推荐的是使用bcrypt加密方式。
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("zhangzhang").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","vip2");
}
这时候就可以正常登录了,但是如果账号没有权限,就会返回403,表示没有权限,如下

账号登录成功后,正常我们会有一个注销的功能,该框架也自带了,只要页面的请求的路径是:/logout 就会走到对应注销,如下:
会返回改框架自带的登录页面
//定制请求的授权规则
@Override
protected void configure(HttpSecurity http) throws Exception {
//....
//开启自动配置的注销的功能
// /logout 注销请求
http.logout();
}

自定义跳转的方法logoutSuccessUrl,不返回默认页面
http.logout().logoutSuccessUrl("/");
如果注销404了,就是因为它默认防止csrf跨站请求伪造,因为会产生安全问题,我们可以将请求改为post表单提交,或者在spring security中关闭csrf功能;配置如下:
http.csrf().disable();//关闭csrf功能:跨站请求伪造,默认只能通过post方式提交logout请求
http.logout().logoutSuccessUrl("/");
该框架还可以授权那些内容对应哪些角色可以观看,这时候需要和前端联调,结合thymeleaf进行配置,首先需要导入依赖:
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
<version>3.0.4.RELEASE</version>
</dependency>
需要在html中引入声明:
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5"
xmlns:th="http://www.thymeleaf.org"
使用如下对应语句,就可以对授权的用户展示对应内容,前端控制!
sec:authorize="!isAuthenticated()"
正常网页中,有一个记住账号密码的功能,对应配置如下:
记住我!
@Override
protected void configure(HttpSecurity http) throws Exception {
http.rememberMe();
}
测试如下:多了一个cookie

结论:登录成功后,将cookie发送给浏览器保存,以后登录带上这个cookie,只要通过检查就可以免登录了。如果点击注销,则会删除这个cookie,具体的原理我们在JavaWeb阶段都讲过了,这里就不在多说了
登录页的定制,前面我们说过,当请求的路径没有被授权,就会返回登录页,但返回的框架自带的登录,如果要定制登录页需要考虑两个信息:
1 怎么去到自定义登录页面
2 登录的信息怎么返回给安全框架
代码如下,框架默认账号密码参数是username和password,所以前端传过来必须这两个参数!当然这两个参数也是可以修改的
.loginPage("/tologin") 表示跳转的请求的连接,我们可以在controller里设置要跳转去哪里
.loginProcessingUrl("/login");表示表单提交的请求路径,需要携带用户密码参数,这个地方要和前端联调
http.formLogin()
.usernameParameter("username")
.passwordParameter("password")
.loginPage("/tologin")
.loginProcessingUrl("/login"); // 登陆表单提交请求
定制页面的记住密码配置,"remember"前端传过来的参数!
http.rememberMe().rememberMeParameter("remember");

浙公网安备 33010602011771号