浅谈SpringSecurity基本原理
什么是SpringSecurity
SpringSecurity是一个基于Spring框架的安全框架,它提供了完善的认证(authentication)和授权(authorization)机制,可用于保护Web应用程序中的敏感资源。
SpringSecurity的基本原理
SpringSecurity的主要组件
SpringSecurity的主要组件包括:
- 认证安全组件(Authentication):负责验证用户身份。
- 授权安全组件(Authorization):负责控制用户对系统资源的访问权限。
- 过滤器安全组件(Filter):拦截用户请求并进行安全验证。
SpringSecurity的认证原理
SpringSecurity的认证原理基于“客户端(或用户)提供的凭据(credentials)”进行验证。凭据可以是用户名和密码、证书、OAuth令牌等。
SpringSecurity认证的大致过程如下:
- 应用程序拦截客户端请求,并将其传递给SpringSecurity过滤器。
- SpringSecurity过滤器验证客户端提供的凭据,并使用AuthenticationManager进行身份验证。
- AuthenticationManager返回一个被验证的Authentication对象。
- 如果Authentication对象不存在,则重新进行验证。否则,将Authentication对象存储在SecurityContextHolder中。
- 认证完成后,SpringSecurity过滤器将请求传递给应用程序处理。
SpringSecurity的授权原理
SpringSecurity的授权原理基于“访问控制列表(Access Control List,ACL)”进行控制。ACL包含资源路径、角色和权限信息。
SpringSecurity授权的大致过程如下:
- 应用程序在调用Controller之前,经过SpringSecurity的过滤器安全组件。
- SpringSecurity过滤器验证客户端的Authorization信息,并获取客户端所属的角色以及访问资源的权限。
- SpringSecurity根据ACL判断访问控制是否合法。
- 如果不合法,SpringSecurity返回拒绝访问的响应码。
- 如果合法,SpringSecurity将请求传递给Controller进行处理。
SpringSecurity示例1
配置SecurityConfig
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/login")
.permitAll().and()
.logout().permitAll()
.and()
.csrf().disable();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
这里使用@EnableWebSecurity注解启用WebSecurity,重载configure(HttpSecurity http)方法,配置请求拦截规则。"/admin/**"路径需要“ADMIN”角色才能访问,其它请求需要经过认证才能访问。我们还可以对登录页面、登出操作、跨站请求伪造防护进行配置。
配置UserDetailsService
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("User " + username + " not found");
}
return new org.springframework.security.core.userdetails.User(user.getUsername(),
user.getPassword(), getAuthorities(user));
}
private Collection<GrantedAuthority> getAuthorities(User user) {
List<GrantedAuthority> authorities = new ArrayList<>();
for (Role role : user.getRoles()) {
authorities.add(new SimpleGrantedAuthority(role.getName()));
}
return authorities;
}
}
这里实现了UserDetailsService接口,重载loadUserByUsername(String username)方法,通过username查询用户,并将它的角色转换成Spring Security的角色。
运行示例
- 使用注解@EnableWebSecurity启用Spring Security。
- 配置AuthenticationManagerBuilder。
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
这里使用自定义的UserDetailsService,同时配置密码编码器BCryptPasswordEncoder。
- 配置控制器
在Controller中,我们使用@RequestMapping注解定义多个请求路径,用于模拟不同权限的访问控制。
@Controller
public class HomeController {
@RequestMapping(value = {"/", "/home"})
public String home() {
return "home";
}
@RequestMapping(value = "/admin")
public String admin() {
return "admin";
}
@RequestMapping(value = "/login")
public String login() {
return "login";
}
@RequestMapping(value = "/403")
public String error403() {
return "403";
}
}
示例代码已上传至GitHub:https://github.com/liaojack8/SpringSecurityDemo。
SpringSecurity示例2
继承WebSecurityConfigurerAdapter
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("admin").password(passwordEncoder().encode("admin")).roles("ADMIN","USER");
auth.inMemoryAuthentication().withUser("user").password(passwordEncoder().encode("user")).roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/user/**").hasRole("USER")
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/login").permitAll()
.and()
.logout().permitAll();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
这里使用内存用户存储进行模拟,并重载configure(HttpSecurity http)方法,配置请求拦截规则。
配置控制器
在Controller中,我们使用@RequestMapping注解定义多个请求路径,用于模拟不同权限的访问控制。
@Controller
public class HomeController {
@RequestMapping(value = {"/", "/home"})
public String home() {
return "home";
}
@RequestMapping(value = "/admin")
public String admin() {
return "admin";
}
@RequestMapping(value = "/user")
public String user() {
return "user";
}
@RequestMapping(value = "/login")
public String login() {
return "login";
}
@RequestMapping(value = "/403")
public String error403() {
return "403";
}
}
示例代码已上传至GitHub:https://github.com/liaojack8/SpringSecurityDemo-InMemory。
结语
通过以上两个示例,我们了解了SpringSecurity的基本原理以及如何在SpringBoot项目中进行配置和使用。同时,了解到SpringSecurity提供了多种认证和授权方式,我们可以根据实际情况进行选择和配置。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:浅谈SpringSecurity基本原理 - Python技术站