springboot&security
Spring Security是一种功能强大、高度可定制的身份验证和访问控制框架。这也是是保护基于Spring的应用程序的标准。
Spring Security是一个专注于向Java应用程序提供身份验证和授权的框架。与所有的Spring项目一样,Spring Security的真正功能在于它可以容易地扩展以满足定制需求。
特性
认证和授权的全面和可扩展的支持
防止攻击,如会话固定、点击劫持、跨站点请求伪造等
Servlet API集成
与Spring Web MVC的可选集成
更多比如和springboot应用集成,与Auth2集成,与jwt集成等等
本篇文章中我们将基于springboot整合spring security5。
目标
基于springboot2.x集成spring security5,实现应用资源的保护:
用户登陆后才能访问服务端资源
拥有特定权限后才能访问受保护资源
技术实现
介于springboot和spring security都是一家的产品,在融合过程中存在天然的优势,基于以上目标,我们大致有一下几点需要注意:
登录接口不需要保护
登录成功和失败都需要有相应的跳转页面
访问受保护资源受限后跳转无权页面
具体底层技术,我们基于springboot2.x+spring security5 +Thymeleaf来实现。
1:引入依赖
除了引入springboot应用所需要的基础依赖之外,还要引入security和thymeleaf依赖:
org.springframework.boot
spring-boot-starter-security
org.springframework.boot
spring-boot-starter-thymeleaf
2:修改配置文件
修改application.properties主配置文件用以支持Thymeleaf:
# thymeleaf
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.mode=HTML
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.content-type=text/html
spring.thymeleaf.cache=false
logging.level.org.springframework.security: INFO
management.endpoints.web.exposure.include=*
3:编写认证管理类
spring security对于用户的登录认证支持两种模式:
内存认证:将用户、密码以及对应的权限存放到内存中,暴露InMemoryUserDetailsManager实例注册到spring容器中,来实现用户登录及权限认证
数据库认证:大多数商业应用都是采用数据库认证,应用中自己实现UserDetailService或者使用JdbcUserDetailsManager来实现数据库认证。
此处为了方便起见,我们使用内存认证,暴露InMemoryUserDetailsManager实例到容器中:
@Order(Ordered.HIGHEST_PRECEDENCE)
@Configuration
public class AuthenticationSecurity {
@SuppressWarnings("deprecation")
@Bean
public InMemoryUserDetailsManager inMemoryUserDetailsManager() throws Exception {
return new InMemoryUserDetailsManager(
User.withDefaultPasswordEncoder().username("admin").password("admin")
.roles("ADMIN", "USER", "ACTUATOR").build(),
User.withDefaultPasswordEncoder().username("user").password("user")
.roles("USER").build());
}
}
这段代码的意思是,我们使用InMemoryUserDetailsManager来实现用户权限认证,初始化了两个用户并设置了相应的密码和权限。
4:配置权限适配
在控制权限的时候,我们需要对一些接口或者url开白名单,比如登录接口如果加权限的话,就永远登录不了了,还有一些认证成功或失败后的url跳转,包括静态资源的过滤。
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled =true)
public class CustomApplicationSecurity extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().fullyAuthenticated()
.and()
.formLogin().loginPage("/login").failureUrl("/login?error")
.and()
.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.and()
.exceptionHandling().accessDeniedPage("/access?error");
// @formatter:on
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/config/**", "/css/**", "/fonts/**", "/img/**", "/js/**");
}
}
自定义配置类并继承WebSecurityConfigurerAdapter重写configure方法:
设置登录接口所有人都可以访问
其他接口都需要认证后才能访问
使用表单登录,指定登录url,并且指定登录失败后的跳转
指定登出路径
指定认证失败后的跳转页面
对于静态资源的访问不做权限管控
5:开启Security功能
在应用启动类上增加注解@EnableWebSecurity:
@SpringBootApplication
@EnableWebSecurity
public class App
{
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
6:编写请求处理器
@Controller
public class HomeController {
@GetMapping("/")
@PreAuthorize("hasRole('ADMIN')")
public String home(Map model) {
model.put("message", "Hello World");
model.put("title", "Hello Home");
model.put("date", new Date());
return "home";
}
@GetMapping("/login")
public String index() {
return "login";
}
}
7:编写页面文件
登录主页面
Login
href="../../css/bootstrap.min.css" />
Thymeleaf -
Plain
Home
You have been logged out
There was an error, please try again
Login with Username and Password
class="btn btn-primary" />
错误页面
Error
href="../../css/bootstrap.min.css" />
Thymeleaf -
Plain Home Logout
Title
July 11,
2012 2:17:16 PM CDT
There was an unexpected error (type=Bad, status=500).
Fake content
Please contact the operator with the above information.
登录成功后主页面
Title
href="../../css/bootstrap.min.css" />
Thymeleaf -
Plain Home Logout
Title
Fake content
July 11,
2012 2:17:16 PM CDT
访问受限后跳转页面
Error
href="../../css/bootstrap.min.css" />
Thymeleaf -
Plain Home Logout
Title
Access denied:
you do not have permission for that resource
Fake content
Please contact the operator with the above information.
测试
启动应用后,浏览器输入localhost:8080/ :
故意输入一个错误的账号密码:
输入普通用户账号和密码:
登录成功了,但是跳转的时候接口有做权限管控,需要ADMIN角色:
输入admin账号和密码:
访问成功。到这里我们也就实现了springboot集成security来实现简单的权限管控。
总结
目前市面上流行的权限管控框架有很多种,比较常用的就是shiro和security,shiro使用起来更简单,security与spring应用能够无缝融合,两者孰好孰坏并没有定论,具体使用哪个,完全取决于开发人员的
技术站或者应用的历史原因。
此篇通过分析和使用代码的方式实现了简单的应用访问权限管控,如果是简单的应用,对于上述的代码把认证管理工具改成数据库的方式就能直接使用,具体的security实现原理和核心类的架构依赖本篇不做赘述。
希望给大家带来一定的参考价值。
领取专属 10元无门槛券
私享最新 技术干货