Spring Security

Spring Security

Spring Security 是 Spring 家族中的一个安全管理框架,但是对比 Shiro 使用的并不多。在Spring Boot中,对 Spring Security 提供了自动化配置方案,可以零配置使用 Spring Security。

常见的安全管理技术栈的组合:

  • SSM(Spring+SpringMVC+MyBatis) + Shiro
  • Spring Boot/Spring Cloud + Spring Security

核心功能:

  • 认证(你是谁)
  • 授权(你能干什么)
  • 攻击防护(防止伪造身份)

项目创建

首先创建spring boot项目,添加依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

创建一个 HelloController:

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

访问 /hello ,需要登录之后才能访问:

当用户从浏览器请求访问 /hello 时,会重定向到 /login 页面,用户登陆成功之后就会自动跳转到 /hello 。
默认情况下,登录的用户名是 user ,密码从启动的控制台日志中得到。

也可以使用 POSTMAN 来发送请求,将用户信息放在请求头中(可以避免重定向到登录页面)。

由此知Spring Security 支持两种不同的认证方式:

  • 可以通过 form 表单来认证
  • 可以通过 HttpBasic 来认证

用户名配置

对登录的用户名/密码进行配置,有三种不同的方式:

  • 在 application.properties 中进行配置
  • 通过 Java 代码配置在内存中
  • 通过 Java 从数据库中加载

在 application.properties 文件中配置用户的基本信息:

spring.security.user.name=test
spring.security.user.password=123456

基于内存来存储用户信息

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception{
        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
                .withUser("user").password(new BCryptPasswordEncoder().encode("123")).roles("USER").and()
                .withUser("admin").password(new BCryptPasswordEncoder().encode("456")).roles("USER","ADMIN");
    }
}

过滤器的使用

对于登录成功或失败后的响应,都可以在 WebSecurityConfigurerAdapter 的实现类中进行配置。
WebSecurityConfigurerAdapter类:通过重载该类的三个configure()方法来制定Web安全的细节。

  • configure(WebSecurity):通过重载该方法,可配置Spring Security的Filter链
  • configure(HttpSecurity):通过重载该方法,可配置如何通过拦截器保护请求
  • configure(AuthenticationManagerBuilder):通过重载该方法,可配置user-detail(用户详细信息)服务

创建Spring Security的配置类

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()    //开启登录配置
                .antMatchers("/", "/home").permitAll()  //访问"/"和"/home"路径的请求都允许
                .anyRequest().authenticated()   //表示剩余的其他接口,登录之后访问
                .and()
                .formLogin()    //表单登陆
                //定义登录页面,未登录时,访问一个需要登录之后才能访问的接口,会自动跳转到该页面
                .loginPage("/login")
                .permitAll()
                .and()
                .logout()
                .permitAll();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception{
        //基于内存来存储用户信息
        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
                .withUser("user").password(new BCryptPasswordEncoder().encode("123")).roles("USER").and()
                .withUser("admin").password(new BCryptPasswordEncoder().encode("456")).roles("USER","ADMIN");
    }
}

Controller层代码

@Controller
public class SecurityController {

    @GetMapping(value = {"/home","/"})
    public String home(){
        return "home";
    }

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

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

模板页面放在resources/templates目录下
home.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
    <head>
        <title>Spring Security Example</title>
    </head>
    <body>
        <h1>Welcome!</h1>
        <p>Click <a th:href="@{/hello}">here</a> to see a greeting.</p>
    </body>
</html>

hello.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
    <head>
        <title>Hello World!</title>
    </head>
    <body>
        <h1 th:inline="text">Hello [[${#httpServletRequest.remoteUser}]]!</h1>
        <form th:action="@{/logout}" method="post">
            <input type="submit" value="Sign Out"/>
        </form>
    </body>
</html>

login.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
    <head>
        <title>登陆</title>
    </head>
    <body>
        <h3>表单登陆</h3>
        <div th:if="${param.error}">
            Invalid username and password.
        </div>
        <div th:if="${param.logout}">
            You have been logged out.
        </div>

        <form th:action="@{/login}" method="post">
            <tr>
                <td>用户名:</td>
                <td><input type="text" name="username"></td>
            </tr>
            <tr>
                <td>密码:</td>
                <td><input type="password" name="password"></td>
            </tr>
            <tr>
                <td colspan="2"><button type="submit">Sign In</button></td>
            </tr>
        </form>
    </body>
</html>

在pom.xml文件中单独添加Thymeleaf依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

运行结果




localhost:8080/home可直接访问,而直接访问 localhost:8080/hello 时,页面将跳转到 localhost:8080/login。在login界面输入SecurityConfig中配置的用户名及密码,将成功跳转到hello界面。

忽略拦截

如果某一个请求地址不需要拦截的话,有两种方式实现:

  • 设置该地址匿名访问
  • 直接过滤掉该地址,即该地址不走 Spring Security 过滤器链

第二种方案:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/vercode");
    }
}
posted @ 2021-03-24 00:59  当康  阅读(98)  评论(0编辑  收藏  举报