springboot-security

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实现原理和核心类的架构依赖本篇不做赘述。

希望给大家带来一定的参考价值。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20181119G00BUQ00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券