SpringSecurity

155 阅读4分钟

1,权限管理框架

为什么需要权限管理框架呢
    1,安全性:防止误操作,人为破坏,数据泄露
    2,数据隔离性:不同的权限能看到以及能操作不同的内容
    3,明确职责:测试,运维等角色的leader和dev不相同
    

image.png

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 }

数据库设计

image.png


开启权限

在 SecurityConfig 头顶上加上 @EnableGlobalMethodSecurity(prePostEnabled= true) 该注解。