Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。

权限控制是非常常见的功能,在各种后台管理里权限控制更是重中之重.在Spring Boot中使用 Spring Security 构建权限系统是非常轻松和简单的.下面我们就来快速入门 Spring Security .在开始前我们需要一对多关系的用户角色类,一个restful的controller.

参考项目代码地址

- 添加 Spring Security 依赖

首先我默认大家都已经了解 Spring Boot 了,在 Spring Boot 项目中添加依赖是非常简单的.把对应的
spring-boot-starter-*** 加到pom.xml文件中就行了

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

- 配置 Spring Security

简单的使用 Spring Security 只要配置三个类就完成了,分别是:

  • UserDetails

这个接口中规定了用户的几个必须要有的方法

public interface UserDetails extends Serializable {

    //返回分配给用户的角色列表
Collection<? extends GrantedAuthority> getAuthorities(); //返回密码
String getPassword(); //返回帐号
String getUsername(); // 账户是否未过期
boolean isAccountNonExpired(); // 账户是否未锁定
boolean isAccountNonLocked(); // 密码是否未过期
boolean isCredentialsNonExpired(); // 账户是否激活
boolean isEnabled();
}
  • UserDetailsService

这个接口只有一个方法 loadUserByUsername,是提供一种用 用户名 查询用户并返回的方法。

public interface UserDetailsService {
UserDetails loadUserByUsername(String var1) throws UsernameNotFoundException;
}
  • WebSecurityConfigurerAdapter

这个内容很多,就不贴代码了,大家可以自己去看.

我们创建三个类分别继承上述三个接口

  • 此 User 类不是我们的数据库里的用户类,是用来安全服务的.
/**
* Created by Yuicon on 2017/5/14.
* https://segmentfault.com/u/yuicon
*/
public class User implements UserDetails { private final String id;
//帐号,这里是我数据库里的字段
private final String account;
//密码
private final String password;
//角色集合
private final Collection<? extends GrantedAuthority> authorities; User(String id, String account, String password, Collection<? extends GrantedAuthority> authorities) {
this.id = id;
this.account = account;
this.password = password;
this.authorities = authorities;
} //返回分配给用户的角色列表
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
} @JsonIgnore
public String getId() {
return id;
} @JsonIgnore
@Override
public String getPassword() {
return password;
} //虽然我数据库里的字段是 `account` ,这里还是要写成 `getUsername()`,因为是继承的接口
@Override
public String getUsername() {
return account;
}
// 账户是否未过期
@JsonIgnore
@Override
public boolean isAccountNonExpired() {
return true;
}
// 账户是否未锁定
@JsonIgnore
@Override
public boolean isAccountNonLocked() {
return true;
}
// 密码是否未过期
@JsonIgnore
@Override
public boolean isCredentialsNonExpired() {
return true;
}
// 账户是否激活
@JsonIgnore
@Override
public boolean isEnabled() {
return true;
}
}
  • 继承 UserDetailsService
/**
* Created by Yuicon on 2017/5/14.
* https://segmentfault.com/u/yuicon
*/
@Service
public class UserDetailsServiceImpl implements UserDetailsService { // jpa
@Autowired
private UserRepository userRepository; /**
* 提供一种从用户名可以查到用户并返回的方法
* @param account 帐号
* @return UserDetails
* @throws UsernameNotFoundException
*/
@Override
public UserDetails loadUserByUsername(String account) throws UsernameNotFoundException {
// 这里是数据库里的用户类
User user = userRepository.findByAccount(account); if (user == null) {
throw new UsernameNotFoundException(String.format("没有该用户 '%s'.", account));
} else {
//这里返回上面继承了 UserDetails 接口的用户类,为了简单我们写个工厂类
return UserFactory.create(user);
}
}
}
  • UserDetails 工厂类
/**
* Created by Yuicon on 2017/5/14.
* https://segmentfault.com/u/yuicon
*/
final class UserFactory { private UserFactory() {
} static User create(User user) {
return new User(
user.getId(),
user.getAccount(),
user.getPassword(),
mapToGrantedAuthorities(user.getRoles().stream().map(Role::getName).collect(Collectors.toList()))
);
} //将与用户类一对多的角色类的名称集合转换为 GrantedAuthority 集合
private static List<GrantedAuthority> mapToGrantedAuthorities(List<String> authorities) {
return authorities.stream()
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
}
}
  • 重点, 继承 WebSecurityConfigurerAdapter 类
/**
* Created by Yuicon on 2017/5/14.
* https://segmentfault.com/u/yuicon
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter { // Spring会自动寻找实现接口的类注入,会找到我们的 UserDetailsServiceImpl 类
@Autowired
private UserDetailsService userDetailsService; @Autowired
public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder
// 设置UserDetailsService
.userDetailsService(this.userDetailsService)
// 使用BCrypt进行密码的hash
.passwordEncoder(passwordEncoder());
} // 装载BCrypt密码编码器
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
} //允许跨域
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*")
.allowedMethods("GET", "HEAD", "POST","PUT", "DELETE", "OPTIONS")
.allowCredentials(false).maxAge(3600);
}
};
} @Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
// 取消csrf
.csrf().disable()
// 基于token,所以不需要session
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
// 允许对于网站静态资源的无授权访问
.antMatchers(
HttpMethod.GET,
"/",
"/*.html",
"/favicon.ico",
"/**/*.html",
"/**/*.css",
"/**/*.js",
"/webjars/**",
"/swagger-resources/**",
"/*/api-docs"
).permitAll()
// 对于获取token的rest api要允许匿名访问
.antMatchers("/auth/**").permitAll()
// 除上面外的所有请求全部需要鉴权认证
.anyRequest().authenticated();
// 禁用缓存
httpSecurity.headers().cacheControl();
}
}

- 控制权限到 controller

使用 @PreAuthorize("hasRole('ADMIN')") 注解就可以了

/**
* 在 @PreAuthorize 中我们可以利用内建的 SPEL 表达式:比如 'hasRole()' 来决定哪些用户有权访问。
* 需注意的一点是 hasRole 表达式认为每个角色名字前都有一个前缀 'ROLE_'。所以这里的 'ADMIN' 其实在
* 数据库中存储的是 'ROLE_ADMIN' 。这个 @PreAuthorize 可以修饰Controller也可修饰Controller中的方法。
**/
@RestController
@RequestMapping("/users")
@PreAuthorize("hasRole('USER')") //有ROLE_USER权限的用户可以访问
public class UserController { @Autowired
private UserRepository repository; @PreAuthorize("hasRole('ADMIN')")//有ROLE_ADMIN权限的用户可以访问
@RequestMapping(method = RequestMethod.GET)
public List<User> getUsers() {
return repository.findAll();
}
}

- 结语

Spring Boot中 Spring Security 的入门非常简单,很快我们就能有一个满足大部分需求的权限系统了.而配合 Spring Security 的好搭档就是 JWT 了,两者的集成文章网络上也很多,大家可以自行集成.因为篇幅原因有不少代码省略了,需要的可以参考参考项目代码

Spring Boot中使用 Spring Security 构建权限系统的更多相关文章

  1. Spring Boot中使用Spring Security进行安全控制

    我们在编写Web应用时,经常需要对页面做一些安全控制,比如:对于没有访问权限的用户需要转到登录表单页面.要实现访问控制的方法多种多样,可以通过Aop.拦截器实现,也可以通过框架实现(如:Apache ...

  2. Spring Boot中使用Swagger2自动构建API文档

    由于Spring Boot能够快速开发.便捷部署等特性,相信有很大一部分Spring Boot的用户会用来构建RESTful API.而我们构建RESTful API的目的通常都是由于多终端的原因,这 ...

  3. Spring Boot 中 10 行代码构建 RESTful 风格应用

    RESTful ,到现在相信已经没人不知道这个东西了吧!关于 RESTful 的概念,我这里就不做过多介绍了,传统的 Struts 对 RESTful 支持不够友好 ,但是 SpringMVC 对于 ...

  4. 【swagger】1.swagger提供开发者文档--简单集成到spring boot中【spring mvc】【spring boot】

    swagger提供开发者文档 ======================================================== 作用:想使用swagger的同学,一定是想用它来做前后台 ...

  5. 在Spring Boot中使用Spring Security实现权限控制

    丢代码地址 https://gitee.com/a247292980/spring-security 再丢pom.xml <properties> <project.build.so ...

  6. Spring Boot中集成Spring Security 专题

    check to see if spring security is applied that the appropriate resources are permitted: @Configurat ...

  7. Spring Boot 中使用 Spring Security, OAuth2 跨域问题 (自己挖的坑)

    使用 Spring Boot 开发 API 使用 Spring Security + OAuth2 + JWT 鉴权,已经在 Controller 配置允许跨域: @RestController @C ...

  8. Spring Boot 中应用Spring data mongdb

    摘要 本文主要简单介绍下如何在Spring Boot 项目中使用Spring data mongdb.没有深入探究,仅供入门参考. 文末有代码链接 准备 安装mongodb 需要连接mongodb,所 ...

  9. 【从0到1,搭建Spring Boot+RESTful API+Shiro+Mybatis+SQLServer权限系统】06、Mybatis+SQLServer集成

    1.增加POM依赖 注意pagehelper插件,我重写过,可以到我的这篇文章了解https://www.cnblogs.com/LiveYourLife/p/9176934.html <dep ...

随机推荐

  1. WPF 杂谈——Trigger触发器

    笔者在使用的WPF过程中,见过的触发器有三种:Trigger.DataTrigger.EventTrigger.其中最为常用的要属Trigger.至于触发器的作用就是当某个属性的值发生变化,应该去做某 ...

  2. app 选项卡代码

    <div id="segmented" class="mui-segmented-control"> <a class="mui-c ...

  3. openssl req(生成证书请求和自建CA)

    伪命令req大致有3个功能:生成证书请求文件.验证证书请求文件和创建根CA.由于openssl req命令选项较多,所以先各举几个例子,再集中给出openssl req的选项说明.若已熟悉openss ...

  4. AngularJS4.0环境搭建详解--windows系统环境

    第一步:安装NodeJS 下载最新版的NodeJS并安装,安装完成后打开CMD命令行,输入以下命令: node -v 若返回类似版本号则代表NodeJS安装成功,如下: 第二部 安装npm 新版的No ...

  5. Postmessage运用-往飞信添加信息

    1.定位窗口 fHwnd:=FindWindow(nil,'短信中心'); then begin showmessage('请先登录飞信2013短信中心'); exit; end; { applica ...

  6. 优雅的封装ajax,含跨域

    之前写过一篇 先定一个小目标,自己封装个ajax,是基于原生js的,也就是jquery中ajax的简化版本实现的思路.众所周知,jquery的ajax是项目中最常用的请求后台的方式,也算是封装的很完美 ...

  7. QQ空间魔力日志大全SduSRZ

    大家好~最近,在QQ空间里出现了一种神奇的日志,谁看显示谁的信息,在个人中心显示的是一张图片,在日志里显示的又是另一张图片.这就是传说中的魔力日志.魔力日志从今年的9月份开始盛行,因为具有谁看就针对谁 ...

  8. Spring Boot 系列(一)快速入门

    简介 Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置 ...

  9. 使用curl模拟ip和来源进行网站采集的实现方法

    对于限制了ip和来源的网站,使用正常的采集方式是不行的.本文将介绍一种方法,使用php的curl类实现模拟ip和来源,实现采集限制ip和来源的网站. 1.设置页面限制ip和来源访问 server.ph ...

  10. Java设计模式之包装模式

    有时候一个对象的方法可能不是我们想要的功能,我们希望能将这个方法覆写.而对于覆写,我们最直白的感觉就是通过子类继承的方式,但是有时候对于使用web开发而言,我们能知道获取对象的实现接口,而真正对象是属 ...