一、spring_security
介绍:
Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。
spring security 的核心功能主要包括:
-
认证 (你是谁)
-
授权 (你能干什么)
-
攻击防护 (防止伪造身份)
核心几个过滤器:
SecurityContextPersistenceFilter :这个Filter是整个拦截过程的入口和出口
UsernamePasswordAuthenticationFilter :用于处理来自表单提交的认证。该表单必须提供对应的用户名和密码,其内部还有登录成功或失败后进行处理的
ExceptionTranslationFilter: 能够捕获来自 FilterChain 所有的异常
FilterSecurityInterceptor: 是用于保护web资源的
一、简单案例
1、创建maven项目
2、pom依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies>
3、编写controller
@RestController
public class UserController {
@RequestMapping("/r/r1")
public String r1(){
return "访问资源";
}
}
4、启动类
@SpringBootApplication
public class Spring_securityApp {
public static void main(String[] args) {
SpringApplication.run(Spring_securityApp.class,args);
}
}
5、启动服务器
6、访问controller
这时候会拦截到登录页面
用户名默认是:user
用户密码在控制台可以看到:
具体以控制台为标准进行登录
类似:Using generated security password: 9231223d-1cf4-4054-bd3c-509d4dd653e1
7、再访问controller这时候会看到资源可以被访问了
二、添加自定义用户
1、pom同上
2、配置WebSecurityConfigurerAdapter
说明:下面2.1和2.2是二选一的直选一个
2_1、内存用户
如果是使用内存用户就用这个
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
//如果是内存用户就用这个 否则直接把它去掉直接换成自己编写的就可以了
@Override
@Bean
public UserDetailsService userDetailsServiceBean() {
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(User.withUsername("name1").password(new BCryptPasswordEncoder().encode("123456")).authorities("name1").build());
manager.createUser(User.withUsername("name2").password(new BCryptPasswordEncoder().encode("123456")).authorities("name2").build());
return manager;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin() // 定义当需要用户登录时候,转到的登录页面。
.and()
.authorizeRequests() // 定义哪些URL需要被保护、哪些不需要被保护
.antMatchers("/name1/**").hasAuthority("name1")
.antMatchers("/name2/**").hasAuthority("name2")
.antMatchers("/name3/**").hasAuthority("name3");
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
// 设置默认的加密方式
return new BCryptPasswordEncoder();
}
}
2_2、数据库用户
如果不使用内存用户就用这个配置
package com.configer;
import com.service.UserDetailsServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import javax.annotation.Resource;
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin() //需要用户登录时候,转到的登录页面,不写将不能跳到登录页面
.and()
.authorizeRequests() // 定义哪些URL需要被保护、哪些不需要被保护
.antMatchers("/name1/**").hasAuthority("name1")
.antMatchers("/name2/**").hasAuthority("name2")
.anyRequest() // 任何请求,登录后可以访问 不写这个将不保护其他资源
.authenticated();
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
// 设置默认的加密方式
return new BCryptPasswordEncoder();
}
}
登录userservice
package com.service;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
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.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
return new User(username, new BCryptPasswordEncoder().encode("123456"),
AuthorityUtils.commaSeparatedStringToAuthorityList("name1,name2,name3"));
}
}
3、controller测试
@RestController
public class UserController {
@RequestMapping("/name1")
public String name1() {
return "name1";
}
@RequestMapping("/name2")
public String name2(){
return "name2";
}
@RequestMapping("/name3")
public String name3(){
return "name3";
}
}
三、添加自定义页面
1、pom同上
2、WebSecurityConfig
package com.config;
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.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
//如果是内存用户就用这个 否则直接把它去掉直接换成自己编写的就可以了
@Override
@Bean
public UserDetailsService userDetailsServiceBean() {
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(User.withUsername("zhnagsan").password(passwordEncoder().encode("123456")).authorities("name1").build());
manager.createUser(User.withUsername("liis").password(passwordEncoder().encode("123456")).authorities("name2").build());
manager.createUser(User.withUsername("wangwu").password(passwordEncoder().encode("123456")).authorities("name1","name2","name3").build());
return manager;
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
// 设置默认的加密方式
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin()
// 定义当需要用户登录时候,转到的登录页面。
.loginPage("/login.html")
// 自定义登录页面必须有这一项否则会登录失败,这个地址是框架提供好的 这里就这么写就可以了
.loginProcessingUrl("/login")
// 这个是登录成功时候的地址,必须是controller地址不能是页面地址否则会报405错误如果不写这个会跳到初始拦截时候的页面
.successForwardUrl("/success")
//登录失败的页面 必须是controller地址不能是页面地址否则会报405错误 如果不写会跳到登录页面再去登录
.failureForwardUrl("/failure")
.and()
// 定义哪些URL需要被保护、哪些不需要被保护
.authorizeRequests()
.antMatchers("/name1/**").hasAuthority("name1")
.antMatchers("/name2/**").hasAuthority("name2")
.antMatchers("/name3/**").hasAuthority("name3")
.and().csrf().disable();//自定义页面一定要关闭csrf,否则会导致登录不成功
}
}
3、controller
package com.Conroller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.security.RolesAllowed;
@Controller
public class UserController {
@RequestMapping("/name1")
@ResponseBody
public String name1() {
return "name1";
}
@RequestMapping("/name2")
@ResponseBody
public String name2(){
return "name2";
}
@ResponseBody
@RequestMapping("/name3")
@RolesAllowed("name1")//这里也可以是注解授权
public String name3(){
return "name3";
}
@RequestMapping("/success")
public String success(){
return "redirect:/success.html";
}
@RequestMapping("/failure")
public String failure(){
return "redirect:/failure.html";
}
}
4、static/login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/login" method="post">
username: <input type="text" name="username"> <br>
password: <input type="password" name="password"> <br>
<input type="submit" value="login">
</form>
</body>
</html>
5、static/success.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
success
</body>
</html>
6、static/failure.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
failure
</body>
</html>