1,权限管理框架
为什么需要权限管理框架呢
1,安全性:防止误操作,人为破坏,数据泄露
2,数据隔离性:不同的权限能看到以及能操作不同的内容
3,明确职责:测试,运维等角色的leader和dev不相同
2,认证和授权
认证和授权是所有权限控制都有的概念,并不是SpringSecurity独有的
3,CSRF攻击
CSRF攻击,跨站请求伪造攻击,利用浏览器对用户网站信任的一种攻击,
简单描述一下攻击流程
1,客户访问A应用的网站,浏览器端已经储存的A网站的Cookie信息;
2,客户打开B网站看到一个感兴趣的链接,而这个链接连接的服务器的某个路径
3,你点了图片就会有意想不到的效果
模拟情景
//第一步:模拟一个银行转账的案例
// 接⼝
@RestController
@RequestMapping("/transfer")
public class TransferController {
@GetMapping
public String transfer(String card, Integer amount) {
System.out.println(String.format("向 %s, 转账 %s 元", card, amount));
return "success";
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>验证码</title>
</head>
<body>
<form action="/transfer">9 Card No: <input name="card" autocomplete="off"><br>
10 Amount: <input name="amount" autocomplete="off"><br>
<input type="submit">
</form>
</body>
</html>
//第二步:给个钓鱼网站
<body>
<!-- 当我们点击该图⽚的时候,会⼜意想不到的惊喜!! -->
<a href="http://localhost:8080/transfer?card=7890&amount=1000">
<img width="100" src="image.jpg" />
</a>
</body>
// 第三步:再给个钓鱼网站
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="jquery-2.1.1.min.js"></script>
</head>
<body>
<a href="javascript: postSubmit()">
<img width="100" src="image.jpg"/>
</a>
<div id="box"></div>
<script>
const box = document.querySelector('#box')
function postSubmit() {
box.innerHTML = `
<form id="form" action="http://localhost:8080/transfer" method="p
Card No: <input name="card" autocomplete="off" value="7890"><23 Amount: <input name="amount" autocomplete="off" value="1000">
<input type="submit">
</form>
document.querySelector('#form').submit()
}
</script>
</body>
</html>
解决办法
只需要前后端分离+token的方式就可以解决这个问题
SpringSecurity的自定义登录逻辑
登录逻辑就是在登录的时候判断账号和密码是否正确
// 第一步:密码加密对象
package com.qfedu.security.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* @ClassName AppConfig
* @Description
* @Author Javen
* @Date 2022/6/17 18:03
* @Version V1.0
**/
@Configuration
16 public class AppConfig {
/**
* 向容器提供密码加密对象
* @return
*/
@Bean
public PasswordEncoder providerEncoder(){
//BCrypt是⼀种不可逆加密⽅式,并且⾃带加盐机制,避免密码通过⼤数据破解。
//BCrypt相对MD5更安全。
return new BCryptPasswordEncoder();
}
}
//// 2. ⾃定义类实现UserDetailsService接⼝,loadUserByUsername⽅法⽤于处理登录业务逻辑
```
package com.qfedu.security.auth;
import org.springframework.beans.factory.annotation.Autowired;
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.password.PasswordEncoder;
/**
11 * @ClassName MyUserDetailsService
12 * @Description
13 *
14 * @Date 2022/6/17 17:59
15 * @Version V1.0
16 **/
public class MyUserDetailsService implements UserDetailsService {
@Autowired
private PasswordEncoder passwordEncoder;
/**
* 此⽅法⽤来处理登录业务逻辑
*
* @param username ⽤⼾登录名
* @return
* @throws UsernameNotFoundException
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoun
//第⼀步:判断username在数据库中是否存在
//第⼆步:判断密码是否正确
//第三步:将从数据库查询出来的⽤⼾名和密码封装到UserDetails对象中并且返回
User user = new User(username,password,authorization);
return user;
}
}
**自定义登录页面**
package com.qfedu.security.auth;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecuri
/**
* @ClassName SecurityConfigAdapter
* @Description
* @Author 千锋Java
* @Date 2022/6/20 08:58
* @Version V1.0
**/
public class SecurityConfigAdapter extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
//formLogin为表单提交配置
http.formLogin()
.loginPage("/login.html")//配置⾃定义登录⻚⾯
//配置登录验证接⼝地址,⽅位/login会执⾏⾃定义的登录逻辑
.loginProcessingUrl("/login")
//登录成功跳转的⻚⾯,只接受post请求
.successForwardUrl("/toMain");
}
}
⾃定义登录⻚⾯的配置中,使⽤到了WebSecurityConfigurerAdapter类,此类⽤于SpringSecurity
常规配置,⽐如登录⻚⾯、认证错误跳转⻚⾯等等,常规配置如下:
@Configuration
2 @EnableWebSecurity
3 public class SecurityConfig extends WebSecurityConfigurerAdapter {
4 // 由于 Spring Security 内部默认对 Http标准状态码实现的不是很好,没有登录确返回403,
5 // 需要让其返回 401
6 private Http401UnauthorizedEntryPoint point;
7 private JwtFilter jwtFilter;//JWT配置,详⻅3.4JWT过滤器
8
9 public SecurityConfig(
10 AutowireCapableBeanFactory autowireCapableBeanFactory,
11 Http401UnauthorizedEntryPoint point,
12 JwtFilter jwtFilter) {
13 // jwt过滤器
14 this.jwtFilter = jwtFilter;
15 this.point = point;
16 }
17
18 @Override
19 protected void configure(HttpSecurity http) throws Exception {
20 // Spring Security 的跨域问题解决⽅案,如果是按照其默认的⽅式来⾛的话
21 // 需要这么来配置
22 http
23 //.cors().configurationSource(corsConfigurationSource())
24 .and()
25 // 配置哪些请求需要认证,哪些请求可以直接放过
26 .authorizeRequests(registry ->
27 registry.antMatchers("/user/**", "/role/**", "/pe
28 .antMatchers("/auth/**").permitAll()
29 )
30 // 禁⽤ spring security 默认的表单模式
31 .formLogin().disable()
32 //添加 Jwt的过滤器
33 .addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.
34 .csrf().disable()
35 .exceptionHandling()
36 .authenticationEntryPoint(point);
37 }
38
39 // 跨域配置
40 public CorsConfigurationSource corsConfigurationSource() {
41 CorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
42 CorsConfiguration corsConfiguration = new CorsConfiguration();
43 corsConfiguration.addAllowedOrigin("*"); //同源配置,*表⽰任何请求都视为同44 corsConfiguration.addAllowedHeader("*");//header,允许哪些header,本案中使⽤
45 corsConfiguration.addAllowedMethod("*"); //允许的请求⽅法,PSOT、GET等
46 ((UrlBasedCorsConfigurationSource) source).registerCorsConfiguration("/**
47 return source;
48 }
49 }
// 401处理
1 @Component
2 public class Http401UnauthorizedEntryPoint implements AuthenticationEntryPoint {
3
4 private final Logger log = LoggerFactory.getLogger(Http401UnauthorizedEntryPo
5
6 /**
7 * Always returns a 401 error code to the client.
8 */
9 @Override
10 public void commence(HttpServletRequest request, HttpServletResponse response
11 ServletException {
12
13 log.debug("Pre-authenticated entry point called. Rejecting access");
14 response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
15 }
16 }
数据库设计
开启权限
在 SecurityConfig 头顶上加上 @EnableGlobalMethodSecurity(prePostEnabled= true) 该注解。