Spring Security

一、基本的概念

1.1 认证、授权、会话

认证(Authentication)

认证是验证用户身份的过程。这通常涉及用户名和密码的验证,但也可以包括其他形式的凭据,如数字证书、生物识别等。

在Java中,你可以通过实现**Authentication**接口或使用现有的安全框架(如Spring Security)来处理认证。在Spring Security中,你可以配置安全策略,包括哪些URL需要认证、如何验证用户凭据等。

授权(Authorization)

授权是确定已认证用户是否有权访问特定资源的过程。这可以基于用户的角色、权限或其他属性。

在Java中,你可以使用基于角色的访问控制(RBAC)或基于声明的访问控制(ABAC)来实现授权。Spring Security提供了强大的授权功能,允许你定义访问控制列表(ACL)或使用注解(如**@PreAuthorize** 、**@PostAuthorize**等)来保护方法或URL。

会话(Session)

会话是用户与应用程序之间的一系列交互。在Web应用程序中,会话通常通过HTTP会话(由服务器管理)或JWT(JSON Web Tokens)等令牌来维护。

在Java的Servlet API中,HttpSession 对象用于管理用户的会话。你可以将会话数据存储在**HttpSession**对象中,并在用户的多个请求之间共享这些数据。然而,请注意,HTTP会话在分布式环境中可能难以管理,因为会话数据通常存储在单个服务器的内存中。

为了解决这个问题,你可以使用基于令牌的会话管理(如JWT)。JWT是一种自包含的令牌,可以在客户端和服务器之间安全地传输用户信息。你可以将JWT作为HTTP请求头的一部分发送,并在服务器端验证它来确定用户的身份和权限。

1.2 RBAC

RBAC(Role-Based Access Control,基于角色的访问控制)是一种广泛使用的访问控制机制,它通过分配角色给用户来管理对资源的访问。在RBAC中,权限不是直接授予用户,而是授予角色,用户通过成为适当角色的成员来获得相应的权限。这种方法简化了权限管理,因为权限的变更只需要在角色级别进行,而不是针对每个用户。

(1)根据角色授权

(2)根据权限授权(推荐)

二、Session

2.1 Session认证的流程通常步骤:

  1. 用户请求登录:用户携带其用户名和密码向服务器发送登录请求。
  2. 服务器验证凭据:服务器收到登录请求后,会验证用户提供的用户名和密码是否正确。
  3. 生成Session:如果用户名和密码验证成功,服务器会生成一个Session对象,该对象包含用户的信息和状态。这个Session对象会保存在服务器端。
  4. 发送Session ID:服务器会生成一个唯一的Session ID,并将其存储在客户端的Cookie中,或者通过其他方式(如URL重写)发送给客户端。客户端在后续的请求中会携带这个Session ID。
  5. 验证Session:当客户端发送新的请求时,会携带之前存储的Session ID。服务器会根据这个Session ID查找对应的Session对象,以验证用户是否已登录以及用户的身份和状态。
  6. 处理请求:如果Session验证成功,服务器会处理客户端的请求,并根据用户的权限和状态返回相应的响应。
  7. Session过期或销毁:如果用户在一段时间内没有活动,或者用户主动退出系统,服务器会销毁相应的Session对象,并清除客户端的Session ID。这样,下次客户端再发送请求时,就无法通过Session验证,需要重新登录。

三、Spring Security

3.1引入依赖

复制代码
<dependency>  
    <groupId>org.springframework.boot</groupId>  
    <artifactId>spring-boot-starter-security</artifactId>  
</dependency>

3.2在启动类上加上@EnableWebSecurity

复制代码
@SpringBootApplication
@EnableWebSecurity
public class SpringSecurityApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringSecurityApplication.class, args);
    }

}

3.3这时候发起请求会跳转登录界面(显示效果如下所示)

默认账号: user

密码会在控制台打印出来:

3.4自定义登录账号和密码(admin)

配置类:

复制代码
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    // 默认URL路径跳转到/login, 此url为spring security所提供
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("redirect:/login");
        // 当用户访问根路径时,将会被重定向到登录页面
    }

    @Bean
    public PasswordEncoder getPasswordEncoder(){
        // 这里返回一个PasswordEncoder实例,用于密码编码。
        // 在实际应用中,应该使用BCryptPasswordEncoder来对密码进行加密。
        // return new BCryptPasswordEncoder(10);
        
        // 下面这行代码是用于测试的,它不对密码进行加密,这在生产环境中是不安全的。
        return NoOpPasswordEncoder.getInstance();
    }

    @Bean
    public UserDetailsService userDetailsService(){
        // 创建一个InMemoryUserDetailsManager实例,用于在内存中存储用户信息。
        InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager(
                // 定义三个用户,分别是admin、manager和worker,并设置他们的密码和权限。
                User.withUsername("admin").password(getPasswordEncoder().encode("admin")).authorities("mobile", "salary").build(),
                User.withUsername("manager").password(getPasswordEncoder().encode("manager")).authorities("salary").build(),
                User.withUsername("worker").password(getPasswordEncoder().encode("worker")).authorities("worker").build()
        );
        return userDetailsManager;
    }


}

3.5 登录成功后的跳转的页面 (main.html)

复制代码
// 启用Spring Security的Web安全功能
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 配置HTTP安全
        http
            // 禁用CSRF保护,这在API服务中通常是有必要的,但在Web应用程序中应谨慎处理
            .csrf().disable()
            // 定义授权请求
            .authorizeRequests()
            // 任何以/mobile/开头的请求都需要用户拥有"mobile"权限
            .antMatchers("/mobile/**").hasAuthority("mobile")
            // 任何以/salary/开头的请求都需要用户拥有"salary"权限
            .antMatchers("/salary/**").hasAuthority("salary")
            // 任何以/common/开头的请求都允许所有用户访问,无需认证
            .antMatchers("/common/**").permitAll()
            // 其他所有请求都需要用户进行认证
            .anyRequest().authenticated()
            .and()
            // 配置表单登录
            .formLogin()
            // 登录成功后默认跳转到/main.html
            .defaultSuccessUrl("/main.html")
            // 登录失败后跳转到/common/loginFailer
            .failureUrl("/common/loginFailer");
    }
}
相关推荐
一只叫煤球的猫11 小时前
写代码很6,面试秒变菜鸟?不卖课,面试官视角走心探讨
前端·后端·面试
bobz96511 小时前
tcp/ip 中的多路复用
后端
bobz96512 小时前
tls ingress 简单记录
后端
皮皮林55113 小时前
IDEA 源码阅读利器,你居然还不会?
java·intellij idea
你的人类朋友13 小时前
什么是OpenSSL
后端·安全·程序员
bobz96513 小时前
mcp 直接操作浏览器
后端
前端小张同学15 小时前
服务器部署 gitlab 占用空间太大怎么办,优化思路。
后端
databook15 小时前
Manim实现闪光轨迹特效
后端·python·动效
武子康16 小时前
大数据-98 Spark 从 DStream 到 Structured Streaming:Spark 实时计算的演进
大数据·后端·spark
该用户已不存在16 小时前
6个值得收藏的.NET ORM 框架
前端·后端·.net