SpringSecurity的demo笔记

参考的优秀的文章

  • https://blog.csdn.net/qq_40298902/article/details/106433192
  • https://www.cnblogs.com/ymstars/p/10626786.html (流程理解)
  • https://juejin.cn/post/6854573217940668430 (快速入门和实战)

理解

  • springsecurity是spring提供的认证授权和攻击防护框架。用来进行安全认证服务。

  • springsecurity充分利用了ioc,aop思想和过滤器。

  • springsecurity的大致流程是通过多个过滤器形成的一条过滤器链来拦截验证请求,通过这条过滤器链才可以访问api。

SpringSecurity的demo笔记

执行流程:

SpringSecurity的demo笔记

过滤器链中主要几个过滤器及其作用:

SecurityContextPersistenceFilter:这个Filter是整个拦截过程的入口和出口

UsernamePasswordAuthenticationFilter:用来处理来自表单提交的认证

FilterSecuritylnterceptor:是用于保护web资源的,使用AccessDecisionManager对当前用户进行授权访问

ExceptionTranslationFilter:捕获来自FilterChain所有的异常并进行处理。但是它只会处理两类异 常:Authentication Exception 和 AccessDeniedException ,其它的异常它会继续抛出。

SpringSecurity的demo笔记

大概流程:

(1)UsernamePasswordAuthenticationFilter获取表单输入的用户名和密码等请求信息,并封装成Token
(2)AuthenticationManager负责将Token委托给DaoAuthenticationProvider进行认证
(3)DaoAuthenticationProvider通过UserDetailsService来加载要验证的用户
(4)最后先校验用户的账号是否被锁了等信息,再校验用户账号和密码
(5)校验成功则可以访问接口,失败则抛出异常

常用的注解:

@PreAuthorize

  • 使用这个注解要先在配置类 SpringSecurityConfig 前加上注解@EnableGlobalMethodSecurity(prePostEnabled=true)

  • 这个注解的作用是过滤权限操作的,只有拥有权限才能执行它标注的方法,例如:

    # 只有当前用户拥有role1角色才能访问/roleAuth
    @PreAuthorize("hasRole('role1')")
    @GetMapping("/roleAuth")
    public String role() {
        return "role_lisi";
    }
    
  • 此外,这个注解也支持多个条件:

    # 访问/test要用户的id小于10且用户名要符合
    @PreAuthorize("#id<10 and principal.username.equals(#username)")
    @GetMapping("/test")
    public String test(Integer id, String username) {
        return "注解test";
    }
    

@PostAuthorize

  • 同样,使用这个注解要在配置类前加上注解:@EnableGlobalMethodSecurity(prePostEnabled=true)

  • 在方法执行后再进行权限验证,适合验证带有返回值的权限,Spring EL 提供 返回对象能够在表达式语言中获取返回的对象returnObject。

    @GetMapping("/helloUser")
    @PostAuthorize(" returnObject!=null &&  returnObject.username == authentication.name")
    public User helloUser() {
            Object pricipal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
            User user;
            if("anonymousUser".equals(pricipal)) {
                user = null;
            }else {
                user = (User) pricipal;
            }
            return user;
    }
    

@Secured

  • 同样,使用这个注解要在配置类前加上注解:@EnableGlobalMethodSecurity(securedEnabled=true)

  • 作用和@PreAuthorize类似:

    # 拥有normal或admin角色权限的用户可以访问/helloUser,这里匹配的字符串要加前缀ROLE_才行
    @GetMapping("/helloUser")
    @Secured({"ROLE_normal","ROLE_admin"})
    public String helloUser() {
        return "hello,user";
    }
    

使用步骤

  • 1. 新建一个springboot项目,引入springweb和springSecurity的包(初始化时选的是war包)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sYGhzCP8-1627379097379)(https://cdn.jsdelivr.net/gh/chenshuai-coder/CDN/img/20210726222643.png)]

创建项目时如果使用war包的方式,则除了主启动类application外,还有一个ServletInitializer类,只在war包项目,即外置servlet容	器项目中存在。

参考文章:https://blog.csdn.net/qq_28289405/article/details/81279742

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cEMjn8Sa-1627379097382)(https://cdn.jsdelivr.net/gh/chenshuai-coder/CDN/img/20210726225638.png)]

package com.mmall;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
public class ServletInitializer extends SpringBootServletInitializer {
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(SpringsecutityApplication.class);
    }
}
  • 2. 编写config配置类
 package com.mmall;
 
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
 import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 import org.springframework.security.config.annotation.web.builders.WebSecurity;
 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;
 
 /**
  * Created with Intellij IDEA
  * Description:
  * user: CoderChen
  * Date: 2021-07-26
  * Time: 15:29
  */
 @EnableWebSecurity
 @EnableGlobalMethodSecurity(prePostEnabled=true)
 @Configuration
 public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
 
     @Autowired
     private MyUserService myUserService;
     @Override
     protected void configure(AuthenticationManagerBuilder auth) throws Exception {
 //        auth.inMemoryAuthentication().withUser("admin").password("123456").roles("admin");
         /*使用内存来存储用户,密码,角色信息*/
         /*BCryptPasswordEncoder() 系统内置的对密码进行加密的类*/
         auth.inMemoryAuthentication().
         passwordEncoder(new BCryptPasswordEncoder())
                 .withUser("root").password(new BCryptPasswordEncoder()
                 .encode("123456")).roles("admin")
                 .and()
                 .withUser("lisi").password(new BCryptPasswordEncoder()
                 .encode("123456")).roles("role1")
                 .and()
                 .withUser("zhangsan").password(new BCryptPasswordEncoder()
                 .encode("123456")).roles("role2");
 
         /*在数据库中存储用户,密码,角色信息
         * 自定义的信息写在MyUserService这个类中*/
         auth.userDetailsService(myUserService);
     }
 
     @Override
     /*定义规则,'/'路径和退出lgout及表单登录不被约束,其他的都要经过验证*/
     protected void configure(HttpSecurity http) throws Exception {
         http.authorizeRequests()
                 .antMatchers("/").permitAll()
                 .anyRequest().authenticated()
                 .and()
                 .logout().permitAll()
                 .and()
                 .formLogin();
         /*关闭默认的csrf*/
         http.csrf().disable();
     }
 
     @Override
     /* * "/js/**","/css/**","img/**"这些资源不拦截 */
     public void configure(WebSecurity web) throws Exception {
         web.ignoring().antMatchers("/js/**","/css/**","img/**");
     }
 }
  • 3. 在controller包下的代码中使用:
package com.mmall.Controller;

import org.apache.catalina.User;
import org.springframework.security.access.prepost.PreAuthorize;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * Created with Intellij IDEA
 * Description:
 * user: CoderChen
 * Date: 2021-07-26
 * Time: 15:35
 */
@RestController
@RequestMapping("")
public class main {
    @GetMapping("/")
    public String index() {
        return "hello,springSecurity";
    }

    @GetMapping("/hello")
    public String hello() {
        return "hello";
    }

    /*这个注解是用来过滤权限的,只有拥有ROLE_role1 权限才能访问
    * 这个注解需要在配置类前加@EnableGlobalMethodSecurity(prePostEnabled=true)才能使用*/
    @PreAuthorize("hasRole('role1')")
    @GetMapping("/roleAuth")
    public String role() {
        return "role_lisi";
    }

    /*对权限的条件验证 使用注解 @PreAuthorize*/
    @PreAuthorize("#id<10 and principal.username.equals(#username) and #user.username.equals(abc)")
    @GetMapping("/test")
    public String test(Integer id, String username, User user) {
        return "注解test";
    }
}
  • 4. 如果不使用内存改用数据库来存储用户,角色,权限,则创建一个MyUserService类来在里边写。
package com.mmall;

import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;

/**
 * Created with Intellij IDEA
 * Description:
 * user: CoderChen
 * Date: 2021-07-26
 * Time: 16:32
 */
@Component
public class MyUserService implements UserDetailsService {
    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        return null;
    }
}
上一篇:springboot 集成websocket 实现集群消息推送


下一篇:Java面试官最爱问的垃圾回收机制,Java编程配置思路详解