Spring Security 是针对Spring项目的安全框架,也是Spring Boot底层安全模块默认的技术选型,他可以实现强大的Web安全控制,对于安全控制,我们仅需要引入 spring-boot-starter-security 模块,进行少量的配置,即可实现强大的安全管理!
- WebSecurityConfigurerAdapter:自定义Security策略
- AuthenticationManagerBuilder:自定义认证策略
- @EnableWebSecurity:开启WebSecurity模式
Spring Security的两个主要目标是 “认证” 和 “授权”(访问控制)
“认证”(Authentication)
身份验证是关于验证您的凭据,如用户名/用户ID和密码,以验证您的身份。
身份验证通常通过用户名和密码完成,有时与身份验证因素结合使用。
“授权” (Authorization)
授权发生在系统成功验证您的身份后,最终会授予您访问资源(如信息,文件,数据库,资金,位置,几乎任何内容)的完全权限。
这个概念是通用的,而不是只在Spring Security 中存在。
目录
一、认证和授权
1、引入 Spring Security 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
2、编写 Spring Security 配置类
@EnableWebSecurity //开启websecurity模式
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//定制请求的授权规则
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/").permitAll()//允许任何人访问该路径
.antMatchers("/level1/**").hasRole("vip1")//只允许vip1访问
.antMatchers("/level2/**").hasRole("vip2")//只允许vip2访问
.antMatchers("/level3/**").hasRole("vip3");//只允许vip3访问
/**
* 没有指定默认的登录,会跳转自动生成的登录页面 /login
* 登录失败重定向到这里 /login?error
*/
http.formLogin();
}
}
3、测试访问:localhost:8080/level1/1
没有访问权限,自动跳转login页面
4、我们可以定义认证规则,重写configure(AuthenticationManagerBuilder auth)方法
//定制认证规则
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
/**
* 在内存中定义,也可以在jdbc中拿
* 密码需要加密才能通过认证,spring security官方推荐的是使用bcrypt加密方式
*/
auth.inMemoryAuthentication()
.passwordEncoder(new BCryptPasswordEncoder())
.withUser("root").password(new BCryptPasswordEncoder().encode("123")).roles("vip1","vip2","vip3")
.and()
.withUser("guest").password(new BCryptPasswordEncoder().encode("123")).roles("vip1");
}
5、测试,登录成功,并且每个角色只能访问自己认证的
二、权限控制和注销
1、开启自动配置的注销的功能
protected void configure(HttpSecurity http) throws Exception {
//开启自动配置的注销的功能
//http.logout(); //注销成功跳转登录页面
http.logout().logoutSuccessUrl("/"); //注销成功跳转首页
}
2、在前端页面增加一个注销的按钮
<a class="item" th:href="@{/logout}">
<i class="address card icon"></i> 注销
</a>
3、测试,登录成功后点击注销,发现注销完毕会跳转到登录页面!
4、如果有个需求:用户没有登录的时候,导航栏上只显示登录按钮,用户登录之后,导航栏可以显示登录的用户信息及注销按钮!还有vip1用户只显示一个功能,vip2用户显示两个功能该如何做呢?
我们需要结合thymeleaf中的一些功能,sec:authorize="isAuthenticated()":是否认证登录!来显示不同的页面
添加thymeleaf-extras-springsecurity依赖
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity4</artifactId>
<version>3.0.4.RELEASE</version>
</dependency>
5、前端页面
引入命名空间:xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5"
<!--如果未登录-->
<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>
<div sec:authorize="isAuthenticated()">
<a class="item" th:href="@{/logout}">
<i class="address card icon"></i> 注销
</a>
</div>
注:thymeleaf-extras-springsecurity只支持springboot2.0.9及以下版本
6、重启测试,如果注销404了,就是因为它默认防止csrf跨站请求伪造,因为会产生安全问题,我们可以将请求改为post表单提交,或者在spring security中关闭csrf功能
protected void configure(HttpSecurity http) throws Exception {
...
http.csrf().disable();//关闭csrf功能:跨站请求伪造,默认只能通过post方式提交logout请求
}
7.重新测试就OK了
三、记住我功能
1、开启记住我功能
protected void configure(HttpSecurity http) throws Exception {
//开启记住我功能
http.rememberMe();
}
2、我们再次启动项目测试一下,发现登录页多了一个记住我功能,我们登录之后关闭 浏览器,然后重新打开浏览器访问,发现用户依旧存在!
在浏览器查看cookie,会看到多了一个remember-me
结论:登录成功后,将cookie发送给浏览器保存,以后登录带上这个cookie,只要通过检查就可以免登录了。如果点击注销,则会删除这个cookie,服务器注销session会话
四、使用自定义的登录页
1、在刚才的登录页配置后面指定 loginpage
protected void configure(HttpSecurity http) throws Exception {
...
http.formLogin().loginPage("/tologin");
}
2、然后前端也需要指向我们自己定义的 login请求
请求跳转登录页面
<a class="item" th:href="@{/toLogin}">
<i class="address card icon"></i> 登录
</a>
controller层
@RequestMapping("/tologin")
public String toLoginPage(){
return "login";//跳转登录页面
}
登录页面
<form id="loginFrom" action="#" th:action="@{/tologin}" method="post">
用户名:<input type="text" name="username"> <br>
密码:<input type="password" name="password"> <br>
<input type="submit" value="登录" >
</form>
注:提交表单路径必须跟 http.formLogin().loginPage配置的一样,或者在配置直接指定请求:
http.formLogin()
.usernameParameter("username") //设置用户参数名,默认参数名为username
.passwordParameter("pwd") //设置密码参数名,默认参数名为password
.loginPage("/toLogin")
.loginProcessingUrl("/login"); // 登陆表单提交请求路径
3、在登录页增加记住我的多选框
<input type="checkbox" name="remember"> 记住我
4、后端验证处理!
//定制记住我的参数!
http.rememberMe().rememberMeParameter("remember");
5、测试,OK