SpringBoot中Security如何使用

这篇文章将为大家详细讲解有关SpringBoot 中Security如何使用,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。

专注于为中小企业提供网站设计制作、做网站服务,电脑端+手机端+微信端的三站合一,更高效的管理,为中小企业泰顺免费做网站提供优质的服务。我们立足成都,凝聚了一批互联网行业人才,有力地推动了上千企业的稳健成长,帮助中小企业通过网站建设实现规模扩充和转变。

什么是SpringSecurity

Security是Spring全家桶中一个安全框架,他的扩展能力非常的强,底层是一条过滤器链。通过简单的配置就可以使用,但通过自己的DIY,可以把每个权限细化到每个链接上去。

shiro没有学,但只推荐学一个安全框架

这里搭建的学习项目都是使用SpringBoot

获取SpringSecurity

你可以在maven官网获取最新版本

SpringBoot 中Security如何使用


    org.springframework.boot
    spring-boot-starter-security
    2.4.2

开始一个SpringBoot项目



    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.4.2
         
    
    com.pipihao
    securitylearn
    0.0.1-SNAPSHOT
    securitylearn
    Demo project for Spring Boot
    
        1.8
    
    
        
            com.alibaba
            druid
            1.1.21
        
        
            org.springframework.boot
            spring-boot-starter-thymeleaf
        
        
            org.springframework.boot
            spring-boot-starter-security
        
        
            org.springframework.boot
            spring-boot-starter-web
        
        
            org.mybatis.spring.boot
            mybatis-spring-boot-starter
            2.1.4
        
        
            MySQL
            mysql-connector-java
            runtime
        
        
            org.projectlombok
            lombok
            true
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
        
            org.springframework.security
            spring-security-test
            test
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
                
                    
                        
                            org.projectlombok
                            lombok
                        
                    
                
            
        
    

项目配置文件

server:
  port: 8001

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/demo?serverTimezone=Asia/Shanghai
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver
  thymeleaf:
    cache: false 
    # 因为Thymeleaf很多有默认配置,所以只关了这个缓存,方便刷新

数据库文件

数据库版本为 8.0


运行项目

SpringBoot 中Security如何使用 SpringBoot 中Security如何使用  

登录

用户名:user

密码:控制台输出的这密码

配置Security

方法一:通过配置文件修改登录账号密码
spring:
  security:
  	user:
  	  name: xx
  	  password: xx
方法二:通过自定义配置SecurityConfig配置类

WebSecurityConfigurerAdapter 类是是Security内置提供了一个默认身份验证的抽象类,继承此抽象类实现configure方法则可以对验证操作实现DIY。[于官方文档 6.3 标题可见]

UserDetailsService接口:查询数据库用户名和密码过程

  • 创建类继承UsernamePasswordAuthenticationFilter,重写三个方法
    *

  • 创建类实现UserDetailService,编写查询数据过程,返回User对象,这个User对象是安全框架提供对象。

  • PasswordEncoder: 数据加密接口,用于返回User对象里面的密码加密

方法三:自定义配置类UserDetailsService

定义不验证链接

@Override
protected void configure(HttpSecurity http) throws Exception {
    /*
        使用and()方法表示关闭XML标记的Java配置,它允许我们继续配置父标记。如果您阅读代码,它也是有道理的。我想配置授权请求并配置表单登录并配置HTTP基本身份验证。
         */
    http
        .authorizeRequests()
        .antMatchers("/","/no").permitAll() //可以直接访问的路径
        .anyRequest().authenticated()
        .and()
        .formLogin()
        .loginPage("/login.html") //配置登录路径
        .loginProcessingUrl("/doLogin")
        .defaultSuccessUrl("/hallo")
        .permitAll()
        ; //设置 登录的网页

    http.csrf().disable(); //如果注释了这一行,全部要用_csrf的对象来验证了
}

配置访问权限/角色

如果是配置访问角色则使用是hasRole与hasAnyRole

这里非常建议点一下看一下hasRole的源码使用Role的时候,User的权限列表是需要加ROLE_前缀的

这里直接使用的是hasAnyAuthority,还有一个方法是hasAuthority

前者可以配置多个权限,而后者只能配置一个权限

接口只是显示一个字符串

@GetMapping("test")
public String sayTest(){
    return "Test";
}
SecurityConfig代码
@Override
protected void configure(HttpSecurity http) throws Exception {
    /*
        使用and()方法表示关闭XML标记的Java配置,它允许我们继续配置父标记。如果您阅读代码,它也是有道理的。我想配置授权请求并配置表单登录并配置HTTP基本身份验证。
         */
    http
        .authorizeRequests()
        .antMatchers("/","/no").permitAll() //可以直接访问的路径
        .antMatchers("/test").hasAnyAuthority("admin") // 访问权限
        .anyRequest().authenticated()
        .and()
        .formLogin()
        .loginPage("/login.html") //配置登录路径
        .loginProcessingUrl("/doLogin")
        .defaultSuccessUrl("/hallo")
        .permitAll()
        ; //设置 登录的网页

    http.csrf().disable(); //如果注释了这一行,全部要用_csrf的对象来验证了
}
UserDetailsImpl代码
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    if(StringUtils.isEmpty(username)){
        throw new RuntimeException("用户名不能为空");
    }
    IUser iUser= userMapper.getUserByUsername(username);
    if(iUser == null){
        throw new UsernameNotFoundException("无此用户");
    }
    /*此处查询用户角色*/

    List grantedAuthorityList =
        AuthorityUtils.createAuthorityList("admin"); // 权限的列表

    return new User(iUser.getUsername(),bCryptPasswordEncoder.encode(iUser.getPassword()),grantedAuthorityList);
}

自定义403界面

// 在此方法内加上一行  protected void configure(HttpSecurity http)
http.exceptionHandling().accessDeniedPage("/unauth.html");

权限注解

@Secured

判断是否有角色,这里匹配的角色需要加前缀ROLE_

@GetMapping("update")
@Secured({"ROLE_manager"})
public String update(){
    return "update";
}

使用其功能时需要在application类上开起

@SpringBootApplication
@MapperScan("com.pipihao.securitylearn.mapper")
@EnableGlobalMethodSecurity(securedEnabled = true)
public class SecuritylearnApplication {
    public static void main(String[] args) {
        SpringApplication.run(SecuritylearnApplication.class, args);
    }
}

UserDetailsServiceImpl

List grantedAuthorityList =
    AuthorityUtils.createAuthorityList("admin","ROLE_manager");
@PreAuthorize & @PostAuthorize

此注解即有权限验证功能,又有角色验证功能

@GetMapping("pre1")
@PreAuthorize("hasAnyRole('ROLE_manager')")
public String prePost1(){
    return "prePost1";
}

@GetMapping("pre2")
@PreAuthorize("hasAnyAuthority('admin')")
public String prePost2(){
    return "prePost2";
}
@SpringBootApplication
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecuritylearnApplication {
    public static void main(String[] args) {
        SpringApplication.run(SecuritylearnApplication.class, args);
    }
}

@PostAuthorize 与@PreAuthorize的区别就是,Pre会先拦截后执行,而PostAuthorize是先执行,后拦截

所以我例子中没有过多的讲

@PreFilter & @PostFilter

Pre是过滤上传的数据,Post过滤返回的数据

@GetMapping("list")
@PostFilter("filterObject.username != 'admin' ")
public List list(){
    List iUsers = new ArrayList<>();
    iUsers.add(new IUser(1,"admin","123"));
    iUsers.add(new IUser(2,"user","123"));
    return iUsers;
}

// Applicationo类上还是要加上下面这个注解,并设置属性值
@EnableGlobalMethodSecurity(prePostEnabled = true)

效果图

SpringBoot 中Security如何使用

上传则是同理,通过注解写好判断,然后测试即可,注:PreFilter过滤的也只是集合和数组

用户注销

/*配置退出登录*/
http.logout().logoutUrl("/logout").logoutSuccessUrl("no").permitAll();

登录后,直接通过浏览器,访问此路径即可(是的,就是如此)

location.href='/logout';

自动登录

下面是尚硅谷老师写的原理图和执行流程

SpringBoot 中Security如何使用

如果是微服务,则把数据库改成redis,把cookie改成jwt生成的token

SpringBoot 中Security如何使用

Security 中的一个类内JdbcTokenRepositoryImpl

的常量CREATE_TABLE_SQL

create table persistent_logins (username varchar(64) not null, series varchar(64) primary key, token varchar(64) not null, last_used timestamp not null)

有兴趣的可以看看源码没兴趣的直接在你使用的数据库内执行上面这行sql创建一个保存登录信息的表

SpringBoot 中Security如何使用

JdbcTokenRepositoryImpl 是PersistentTokenRepository实现类
下面这种写那么应该是多态了

@Autowired
private DataSource dataSource;

@Bean
public PersistentTokenRepository persistentTokenRepository(){
    JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
    jdbcTokenRepository.setDataSource(dataSource);
    //jdbcTokenRepository.setCreateTableOnStartup(true); 设置启动时创建自动登录表
    return jdbcTokenRepository;
}

SecurityConfig的方法

@Override
protected void configure(HttpSecurity http) throws Exception {
    /*自定义403链接*/
    http.exceptionHandling().accessDeniedPage("/unauth.html");
    /*配置退出登录*/
    http.logout().logoutUrl("/logout").logoutSuccessUrl("/no").permitAll();
    /*
        使用and()方法表示关闭XML标记的Java配置,它允许我们继续配置父标记。如果您阅读代码,它也是有道理的。我想配置授权请求并配置表单登录并配置HTTP基本身份验证。
         */
    http
        .authorizeRequests()
        .antMatchers("/","/no").permitAll() //可以直接访问的路径
        .antMatchers("/test").hasAnyAuthority("admin")
        .antMatchers("/unauth").hasAnyAuthority("xxx")
        .anyRequest().authenticated()
        .and()
        .formLogin()
        .loginPage("/login.html") //配置登录路径
        .loginProcessingUrl("/doLogin")
        .defaultSuccessUrl("/hallo")
        .permitAll()
        
        // -------------------就是下面这坨
        .and()
        .rememberMe().tokenRepository(persistentTokenRepository())
        .tokenValiditySeconds(60) // 自动保存的时间,秒为单位
        .userDetailsService(userDetailsService)
        ; //设置 登录的网页

    http.csrf().disable(); //如果注释了这一行,全部要用_csrf的对象来验证了
}

下面是登录界面


    user:
    pswd:
         自动登录 
    

然后在登录的时候打个勾,就可以自动登录了

在DB中会出现如下的信息

SpringBoot 中Security如何使用

CSRF指令认证

第一步把下面这一行注释了就开启了,也就是说他其实是默认开启的

如果没有关闭,则会NullPointerException

//http.csrf().disable();

Spring Security CSRF 会针对Patch,Post,Put,Delete方法进行防护。(都是一些要更改数据的方法)

系统默认提供了一个csrfToken对象放在HttpSession中,也就是我们所见到了_csrf对象

此对象可以直接使用

开启CSRF后,则登录的时【POST】,也需要验证CSRF,而使用HttpSession则需要使用模板引擎,这里我们使用的是Thymeleaf而非JSP。(大同小异)

注:使用Thymeleaf的时候,类上的Controller注解不能写成RestController,不然无法生效的

@Controller
public class LoginController {

    @GetMapping("login")
    public String login(){
        return "login";
    }
}



    
    
    
    登录




    user:
    pswd:
         自动登录 
    

切记,默认开了CSRF,则每个表单中应当手动添加一个隐藏域

当Thymeleaf因为你使用了th,则自动给你生成了。

所以 th:action="'/doLogin'" 这样写可以省事

如下图

SpringBoot 中Security如何使用

关于SpringBoot 中Security如何使用就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。


分享题目:SpringBoot中Security如何使用
文章位置:http://azwzsj.com/article/jpgddj.html