Spring Boot与安全
一、常用安全框架
apache shiro
Spring Security
Springboot能整合Spring Security
二、Springboot整合Spring Security
1.认证和和授权的概念
- “认证”(Authentication)是建立用户的过程,就是将你携带的用户名和密码进行确认,看你是否是这个人
- “授权”(Authorization)是在访问过程中看认证过的用户是否具有访问这个资源链接的权限
2.在Pom.xml中引入Spring Security的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
3.编写Spirng Security的配置类
官方文档:https://docs.spring.io/spring-security/site/docs/5.0.16.RELEASE/reference/htmlsingle/
快速开始:https://spring.io/guides/gs/securing-web/
官方配置类
package com.example.securingweb;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
@Bean
@Override
public UserDetailsService userDetailsService() {
UserDetails user =
User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
}
我的配置
@EnableWebSecurity
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
//super.configure(auth);
//定制请求的授权规则
http.authorizeRequests().antMatchers("/").permitAll()//所有都可以登录"/"
.antMatchers("/level1/**").hasRole("VIP1")//Vip1才能访问
.antMatchers("/level2/**").hasRole("VIP2")//Vip1才能访问
.antMatchers("/level3/**").hasRole("VIP3");//Vip3才能访问
//开启自动配置的登录功能,没有权限就跳转登录页面
// 会来到登录页/login
//如果错误会跳转到/login?error
//.loginPage()修改登录页面,如果定制了登录界面,在登录时给定制的登录页面发送post请求即可,携带账号密码参数
//.usernameParameter()定制username传参的name属性.默认使用name="username"
//.passwordParameter()定制password传参的name属性.默认使用name="password"
http.formLogin().loginPage("/userlogin");
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//super.configure(auth);
//定义授权规则
auth.inMemoryAuthentication().withUser("zhangsan").password("123456").roles("VIP1","VIP2")//定义一个用户,权限是role传入的可变数组
.and()
.withUser("lisi").password("123456").roles("VIP2","VIP3")//定义一个用户,权限是role传入的可变数组
.and()
.withUser("wangwu").password("123456").roles("VIP1","VIP2","VIP3");
}
}
遇到问题:异常java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"
解决办法:创建一个PasswordEncoding组件
@Component
public class PasswordEncoding implements PasswordEncoder {
@Override
public String encode(CharSequence charSequence) {
return charSequence.toString();
}
@Override
public boolean matches(CharSequence charSequence, String s) {
return s.equals(charSequence.toString());
}
}
html文档
<!--导入名称空间-->
<html xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
新文档:https://github.com/thymeleaf/thymeleaf-extras-springsecurity
注入的依赖springsecurity5:
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
<version>3.0.4.RELEASE</version>
</dependency>
具体在我的笔记有:
https://blog.csdn.net/qq_41522089/article/details/106820932
4.配置类中的注销功能
@EnableWebSecurity
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
//super.configure(auth);
//定制请求的授权规则
http.authorizeRequests().antMatchers("/").permitAll()//所有都可以登录"/"
.antMatchers("/level1/**").hasRole("VIP1")//Vip1才能访问
.antMatchers("/level2/**").hasRole("VIP2")//Vip1才能访问
.antMatchers("/level3/**").hasRole("VIP3");//Vip3才能访问
//开启自动配置的登录功能,没有权限就跳转登录页面
// 会来到登录页/login
//如果错误会跳转到/login?error
//.loginPage()修改登录页面,如果定制了登录界面,在登录时给定制的登录页面发送post请求即可,携带账号密码参数
//.usernameParameter()定制username传参的name属性.默认使用name="username"
//.passwordParameter()定制password传参的name属性.默认使用name="password"
http.formLogin().loginPage("/userlogin");
//开启注销功能
http.logout().logoutSuccessUrl("/");//注销成功后要去的网站,这里意思是首页
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//super.configure(auth);
//定义授权规则
auth.inMemoryAuthentication().withUser("zhangsan").password("123456").roles("VIP1","VIP2")//定义一个用户,权限是role传入的可变数组
.and()
.withUser("lisi").password("123456").roles("VIP2","VIP3")//定义一个用户,权限是role传入的可变数组
.and()
.withUser("wangwu").password("123456").roles("VIP1","VIP2","VIP3");
}
}
5.rememberme功能
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
//super.configure(auth);
//定制请求的授权规则
http.authorizeRequests().antMatchers("/").permitAll()//所有都可以登录"/"
.antMatchers("/level1/**").hasRole("VIP1")//Vip1才能访问
.antMatchers("/level2/**").hasRole("VIP2")//Vip1才能访问
.antMatchers("/level3/**").hasRole("VIP3");//Vip3才能访问
//开启自动配置的登录功能,没有权限就跳转登录页面
// 会来到登录页/login
//如果错误会跳转到/login?error
//.loginPage()修改登录页面,如果定制了登录界面,在登录时给定制的登录页面发送post请求即可,携带账号密码参数
//.usernameParameter()定制username传参的name属性.默认使用name="username"
//.passwordParameter()定制password传参的name属性.默认使用name="password"
http.formLogin().loginPage("/userlogin");
//开启注销功能
http.logout().logoutSuccessUrl("/");//注销成功后要去的网站,这里意思是首页
//开启记住我的功能
//登录成功后,将cookie放入浏览器,保存14天,如果注销则会删除cookie
//rememberMeParameter("remember")定制remember-me传参的name属性.默认使用name="remember-me"
http.rememberMe().rememberMeParameter("remember");
}