在日常开发中,难免会遇到权限相关的需求,关于权限处理这一块,用的比较多的安全框架分别是Shiro和Spring全家桶中的
Spring-Security,之前已经使用过Shiro,对它也有一定的了解,下面是对Spring-Security学习做的记录。
Spring Security 是一个能够为基于 Spring 的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在 Spring 应用上下文中配置的 Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和 AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。
先用一个比较简单的基于角色访问权限的小例子入门
导入相关jar包,SpringBoot-Utils模块是我常用的一些公共类
compile project(':SpringBoot-Utils')
compile group: 'org.springframework.boot', name: 'spring-boot-starter-security', version: '2.0.5.RELEASE'
compile group: 'org.springframework.boot', name: 'spring-boot-starter-thymeleaf', version: '2.0.5.RELEASE'
compile 'org.thymeleaf.extras:thymeleaf-extras-springsecurity4:3.0.2.RELEASE'
配置Security
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private AccessDeniedHandler accessDeniedHandler;
@Bean
@Override
protected UserDetailsService userDetailsService() {
//直接建两个用户存在内存中,生产环境可以从数据库中读取,对应管理器JdbcUserDetailsManager
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
// 创建两个用户
//通过密码的前缀区分编码方式,推荐,这种加密方式很好的利用了委托者模式,使得程序可以使用多种加密方式,并且会自动
//根据前缀找到对应的密码编译器处理。
manager.createUser(User.withUsername("guest").password("{bcrypt}" +
new BCryptPasswordEncoder().encode("123456")).roles("USER").build());
manager.createUser(User.withUsername("root").password("{sha256}" +
new StandardPasswordEncoder().encode("666666"))
.roles("ADMIN", "USER").build());
return manager;
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
/**
* 支持多种编码,通过密码的前缀区分编码方式,推荐
*
* @return the password encoder
*/
@Bean
PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:on
http.authorizeRequests()
.antMatchers("/css/**", "/js/**", "/fonts/**").permitAll() // 允许访问资源
.antMatchers("/", "/home", "/about", "/login").permitAll() //允许访问这三个路由
.antMatchers("/admin/**").hasAnyRole("ADMIN") // 满足该条件下的路由需要ROLE_ADMIN的角色
.antMatchers("/user/**").hasAnyRole("USER") // 满足该条件下的路由需要ROLE_USER的角色
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll()
.and()
.exceptionHandling().accessDeniedHandler(accessDeniedHandler).and()
.csrf().disable();
// @formatter:off
}
}
上面的代码主要配置了两个用户,分别是root和guest,并分别设置了角色,接着配置静态资源、登录页、首页允许访问,
部分路由指定特定角色可以访问,并配置权限拒绝访问异常处理器和跨越无效。
权限拒绝访问处理器,配置跳转到特定页面
@Component
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
private static Logger logger = LoggerFactory.getLogger(CustomAccessDeniedHandler.class);
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
Authentication auth
= SecurityContextHolder.getContext().getAuthentication();
if (auth != null) {
logger.info("User '" + auth.getName()
+ "' attempted to access the protected URL: "
+ httpServletRequest.getRequestURI());
}
httpServletResponse.sendRedirect(httpServletRequest.getContextPath() + "/403");
}
}
下面访问,/admin,会自动跳转到/login登录页,使用root账号登录,在访问/admin,会发现访问到了。
接着在注销,使用guest的账号登录,会发现自动跳转到了403页面,也就是访问被拒绝了。
原因是guest只配置Role为USER,而访问/admin需要有ADMIN的角色。
到这里,简单的通过角色限制资源访问以实现了,后面如果真是有需要要用到,可自行改造。
比如账号的管理可以从内存移至数据库中等等。
最后,在记录几处采坑的地方:
/**
* 支持多种编码,通过密码的前缀区分编码方式,推荐
* 对应的密码需加上加密算法标识,如:{bcrypt}、{MD5}..........
* @return the password encoder
*/
@Bean
PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
This is a thymeleaf extras module, not a part of the Thymeleaf core (and as such following its own versioning schema), but fully supported by the Thymeleaf team.
This repository contains 3 projects:
thymeleaf-extras-springsecurity3 for integration with Spring Security 3.x
thymeleaf-extras-springsecurity4 for integration with Spring Security 4.x
thymeleaf-extras-springsecurity5 for integration with Spring Security 5.x
Current versions:
Version 3.0.4.RELEASE - for Thymeleaf 3.0 (requires Thymeleaf 3.0.10+)
Version 2.1.3.RELEASE - for Thymeleaf 2.1 (requires Thymeleaf 2.1.2+)
按官方描述,我用的是Spring Security5.X的包,应该使用thymeleaf-extras-springsecurity5的包,但它确不生效。
无奈之下尝试使用thymeleaf-extras-springsecurity4的包,便可以了,这里建议5.0.X的还是用
thymeleaf-extras-springsecurity4的包,毕竟亲测生效了。
项目源码地址:
https://github.com/liaozihong/SpringBoot-Learning/tree/master/SpringBoot-SpringSecurity
参考链接:
https://docs.spring.io/spring-security/site/docs/5.2.0.BUILD-SNAPSHOT/reference/htmlsingle/
https://blog.csdn.net/alinyua/article/details/80219500
https://juejin.im/entry/5a45fe8e6fb9a045132b0658
https://segmentfault.com/a/1190000015191298