详解 Spring Boot Spring Security 中的注销和权限控制问题
前言
Spring Boot Spring Security 是一个非常常用的技术组合,它们可以提供很好的安全性,和身份认证、授权、限制等重要功能,但是在实际开发中可能会遇到注销和权限控制相关的问题,需要我们了解并深入研究。
正文
注销功能
注销功能是常见的需求,用户在退出应用之前需要先注销,以免敏感信息泄露。在 Spring Security 中,我们可以通过配置实现注销功能。
首先,我们需要在 Spring Security 的配置类中添加注销的代码:
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/")
.invalidateHttpSession(true)
.clearAuthentication(true)
.deleteCookies("JSESSIONID");
}
}
上述代码中,我们通过 logout()
方法实现注销功能。其中,参数 .logoutUrl("/logout")
用于指定注销 URL 地址,.logoutSuccessUrl("/")
用于指定注销成功后跳转到的URL地址,.invalidateHttpSession(true)
用于清除会话中的资源,在我们给用户分配的权限需要在会话中持久化的时候,需要把会话中的所有信息清除,.clearAuthentication(true)
用于清除身份验证信息,.deleteCookies("JSESSIONID")
需要删除所有的会话 cookies。
我们还需要在 Spring Boot 应用中添加与实现注销功能相关的接口方法:
@Controller
public class LogoutController {
@RequestMapping(value="/logout", method = RequestMethod.GET)
public String logout(HttpServletRequest request, HttpServletResponse response) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null){
new SecurityContextLogoutHandler().logout(request, response, auth);
}
return "redirect:/login?logout";
}
}
这里我们通过 SecurityContextHolder.getContext().getAuthentication()
获取认证信息,再通过 SecurityContextLogoutHandler().logout(request, response, auth)
处理注销,在完成注销后跳转到登录页面并携带提示信息。
权限控制
权限控制是指针用户访问特定资源时,需要满足一定的条件才能访问。在 Spring Security 中,我们可以通过配置 HttpSecurity
实现权限控制。
在权限控制时,我们需要实现一个自定义的 UserDetailsService
。下面是实现方法示例:
@Service
public class MyUserDetailsService implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Optional<User> userOptional = userRepository.findByUsername(username);
User user = userOptional.orElseThrow(() -> new UsernameNotFoundException(String.format("User %s not found!", username)));
return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), getAuthority());
}
private List<SimpleGrantedAuthority> getAuthority() {
return Arrays.asList(new SimpleGrantedAuthority("ROLE_USER"));
}
}
然后我们在 Spring Security 中配置权限控制:
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private MyUserDetailsService myUserDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(myUserDetailsService);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/user/**").hasRole("USER")
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/")
.invalidateHttpSession(true)
.clearAuthentication(true)
.deleteCookies("JSESSIONID");
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
在上述配置中,我们通过 .antMatchers()
指定需要限制的路径和需要满足的条件,在这里使用了 hasRole("ADMIN")
和 hasRole("USER")
指定了访问这些路径的角色,.anyRequest().authenticated()
表示所有的请求都需要认证以后才能请求,这很重要,否则授权可能不起作用。
示例
注销功能示例:
在 HTML 页面中添加注销按钮:
<a th:href="@{/logout}">Logout</a>
然后处理注销请求的 Controller:
@Controller
public class LogoutController {
@RequestMapping(value="/logout", method = RequestMethod.GET)
public String logout(HttpServletRequest request, HttpServletResponse response) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null){
new SecurityContextLogoutHandler().logout(request, response, auth);
}
return "redirect:/login?logout";
}
}
权限控制示例:
在 HTML 页面中添加不同的请求路径:
<a th:href="@{/admin/hello}">Hello for Admin</a>
<a th:href="@{/user/hello}">Hello for User</a>
然后在 Controller 中处理这些请求:
@Controller
public class HomeController {
@RequestMapping(value={"/", "/home"})
public String home(){
return "home";
}
@RequestMapping(value="/admin/hello", method = RequestMethod.GET)
public String helloAdmin(){
return "hello_admin";
}
@RequestMapping(value="/user/hello", method = RequestMethod.GET)
public String helloUser(){
return "hello_user";
}
}
最后在 mySQL 数据库中添加用户和角色信息:
username | password | role |
---|---|---|
admin | 123456 | ADMIN |
user | 123456 | USER |
这样,我们就可以实现注销和权限控制的功能。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解springboot springsecuroty中的注销和权限控制问题 - Python技术站