Series of articles
SpringBoot 01-HelloSpringBoot, yaml configuration, data verification, multi-environment switching
SpringBoot 02-Simple Web exploration, employee management system
SpringBoot 03-Spring Security
SpringBoot 04-Shiro
Article Directory
Eleven, Spring Security
Introduction
Spring Security is a powerful and highly customizable framework for authentication and access control. It is a standard for protecting Spring-based applications.
Spring Security is to solve the security problem of Web development, just like the filters and interceptors we wrote before, and Spring Security is equivalent to a framework of filters, which can help us omit a lot of code.
For example, we used interceptors or filters to control access before, requiring users to log in to enter the main page, or the pages entered by users with different permissions are not the same, but the code written before is more complicated and redundant, and use The framework can be easily implemented.
There are a few key categories to remember :
- WebSecurityConfigurerAdapter: custom security policy
- AuthenticationManagerBuilder: custom authentication strategy
- @EnableWebSecurity: Turn on the WebSecurity function (seeing @EnableXXX is to turn on a certain function)
The two main goals of Spring Security are "authentication" and "authorization" (that is, access control). Shiro learned later is the same.
Official document: https://spring.io/guides/gs/securing-web/
Let's build a regular SpringBoot Web project.
11.1 Construction of experimental environment
1. Create a SpringBoot project, add a Web module, and import the Thymeleaf package.
<!--thymeleaf—— 命名空间xmlns:th="http://www.thymeleaf.org“ -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
2. Import the static resource file (you can find it from the Internet, you don’t need this step, just to make the interface look better, the current operation does not involve security)
Resource download link
Link: https://pan.baidu.com/s/1UoUJg6CsHm5bQbouYt609A Extraction code: nv8p
CSDN:https://download.csdn.net/download/qq_39763246/15982736
Need to turn off the cache of Thymeleaf
3. Write a routing and forwarding Controller to forward each page.
package com.zcy.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
//用户路由转发的Controller
public class RouterController {
//输入 localhost:8080或者localhost:8080/index都会跳转到首页
@RequestMapping({
"/index", "/"})
public String index(){
return "index";
}
@RequestMapping("/toLogin")
public String toLogin(){
return "views/login";
}
//通过Restful风格,在URL输入 level1/1就会跳转到1.html,输入level2/2就跳转到2.html
@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. Effect
11.2 Authentication and authorization
Create a new SecurityConfig.java
package com.zcy.config;
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.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
//这里用到了AOP,横切的思想,不会去改变我们Controller的代码。类似于拦截器,但更强大!
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//授权
@Override
protected void configure(HttpSecurity http) throws Exception {
//链式编程
//实现的功能:首页index 所有人都能访问,具体的功能也level 只能被有相应权限的人访问
//给请求添加规则,使的访问level1下的所有请求都要有vip1权限
http.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/level1/**").hasRole("vip1")
.antMatchers("/level2/**").hasRole("vip2")
.antMatchers("/level3/**").hasRole("vip3");
//如果没有权限,默认跳转至登录页面。这是Spring Security里内置的
http.formLogin();
}
//认证(Spring Security 5.0+ 要求对密码加密才能正常使用)
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//从内存中读取用户(提前设定好的用户,真实开发还是从数据库中读取,后面Shiro再讲)
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("zcy1").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1")
.and()
.withUser("zcy2").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1", "vip2")
.and()
.withUser("zcy3").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1", "vip2", "vip3");
//从数据库读用户
}
}
effect:
1. When you visit each page when you are not logged in, you will be redirected to the login page. It can be found that the request in the URL bar is /login, but we did not write this page, our login is views/login. This page is http.formLogin();
provided in Spring Security .
http.formLogin();
Annotation of the source code:
2. The login user zcy1 has only the privileges of vip1 and can only access the pages under level1, and access to other pages will be blocked.
3. Login user zcy3, who owns vip1, vip2, vip3, can access all pages.
11.3, logout and permission control
Effect picture:
- When not logged in
- Log in to zcy1 (note that we do not have a customized login page at this time, we use the built-in security, so clicking the login button is invalid, only URL input /login)
-
Log out of zcy1 and return to the homepage
-
Login to zcy2
Implementation:
1. Add logout in index.html
<!--登录注销-->
<div class="right menu">
<!--未登录-->
<a class="item" th:href="@{/toLogin}">
<i class="address card icon"></i> 登录
</a>
<!-- 注销 -->
<a class="item" th:href="@{/logout}">
<i class="sign-out card icon"></i> 注销
</a>
</div>
2. Add logout in SecurityConfig.java
//授权
@Override
protected void configure(HttpSecurity http) throws Exception {
//链式编程
//实现的功能:首页index 所有人都能访问,具体的功能也level 只能被有相应权限的人访问
//给请求添加规则,使的访问level1下的所有请求都要有vip1权限
http.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/views/level1/**").hasRole("vip1")
.antMatchers("/views/level2/**").hasRole("vip2")
.antMatchers("/views/level3/**").hasRole("vip3");
//如果没有权限,默认跳转至一个内置登录页面/login。这是Spring Security里内置的。
http.formLogin(); //.loginPage("可以在这里指定自己的登录页面);
//关闭网站防攻击,默认会开启,因为我们前端用的<a>,是用get方式提交,不安全。
http.csrf().disable();//如果没有这句,注销会404
//开启注销功能,logoutSuccessUrl作用是注销成功跳转到新url,点击注销跳转到首页
http.logout().logoutSuccessUrl("/");
}
http.logout()
Source code comments:
3. Thymeleaf integrates Spring Security
Our original customized homepage used the back end to pass the value to the front end, the front end judged, and then displayed, for example
<div th:if="${session.user.name}">
...显示专属内容
</div>
Now we directly integrate Spring Security in Thymeleaf
- Pilot package
<!-- https://mvnrepository.com/artifact/org.thymeleaf.extras/thymeleaf-extras-springsecurity4 -->
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity4</artifactId>
<version>3.0.4.RELEASE</version>
</dependency>
-
Reduce the Spring Boot version to 2.0.7 (Thymeleaf does not support higher versions to integrate Security, and now generally does not integrate Security)
After lowering, the new version will be downloaded, version 2.0.7, we also need to change the junit package, see the picture below for details.
-
Modify index.html
11.4, remember me and customized login page
1. Remember me: do not log out, you will automatically log in when you re-enter the page
Add code to the configure method of SecurityConfig.java:
//记住我,原理:添加Cookie到浏览器,关闭浏览器重新进入页面后保持登录状态
http.rememberMe();//默认保存两周
effect:
2. Customize the login page
Modify the configure method of SecurityConfig.java:
//如果没有权限,默认跳转至一个内置登录页面/login。这是Spring Security里内置的。
//usernameParameter和passwordParameter指定前端传递过来的参数名称
//loginPage指定自己的登录页面
http.formLogin()
.loginPage("/toLogin")
.usernameParameter("user")
.passwordParameter("pwd");
//.loginProcessingUrl("/login")可指定真正的URL,即在浏览器输入/toLogin,但请求是/login
//记住我,原理:添加Cookie到浏览器,关闭浏览器重新进入页面后保持登录状态
//默认保存两周.rememberMeParameter指定前端传递的参数名称
http.rememberMe()
.rememberMeParameter("remember");
Modify index.html, the original parameter names are username and password, now they are modified. And add a radio button, remember me.
Effect: Click the login button on the homepage to log in normally, and it has the remember me function.