Spring Boot Security入门案例

180 阅读4分钟

一、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>