一、基本的概念
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认证的流程通常步骤:
- 用户请求登录:用户携带其用户名和密码向服务器发送登录请求。
- 服务器验证凭据:服务器收到登录请求后,会验证用户提供的用户名和密码是否正确。
- 生成Session:如果用户名和密码验证成功,服务器会生成一个Session对象,该对象包含用户的信息和状态。这个Session对象会保存在服务器端。
- 发送Session ID:服务器会生成一个唯一的Session ID,并将其存储在客户端的Cookie中,或者通过其他方式(如URL重写)发送给客户端。客户端在后续的请求中会携带这个Session ID。
- 验证Session:当客户端发送新的请求时,会携带之前存储的Session ID。服务器会根据这个Session ID查找对应的Session对象,以验证用户是否已登录以及用户的身份和状态。
- 处理请求:如果Session验证成功,服务器会处理客户端的请求,并根据用户的权限和状态返回相应的响应。
- 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");
}
}