全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

Spring Boot中使用 Spring Security 构建权限系统的示例代码

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.
 */
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.
 */
@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.
 */
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.
 */
@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  # security  # 权限  # boot 


相关文章: 如何通过虚拟机搭建网站?详细步骤解析  微信小程序 input输入框控件详解及实例(多种示例)  XML的“混合内容”是什么 怎么用DTD或XSD定义  开封网站制作公司,网络用语开封是什么意思?  企业在线网站设计制作流程,想建设一个属于自己的企业网站,该如何去做?  全景视频制作网站有哪些,全景图怎么做成网页?  广州营销型建站服务商推荐:技术优势与SEO优化解析  平台云上自主建站:模板化设计与智能工具打造高效网站  百度网页制作网站有哪些,谁能告诉我百度网站是怎么联系?  ,购物网站怎么盈利呢?  h5在线制作网站电脑版下载,h5网页制作软件?  西安专业网站制作公司有哪些,陕西省建行官方网站?  制作网站软件推荐手机版,如何制作属于自己的手机网站app应用?  如何在Golang中使用encoding/gob序列化对象_存储和传输数据  微信h5制作网站有哪些,免费微信H5页面制作工具?  建站三合一如何选?哪家性价比更高?  网站制作模板下载什么软件,ppt模板免费下载网站?  C++中引用和指针有什么区别?(代码说明)  ,有什么在线背英语单词效率比较高的网站?  建设网站制作价格,怎样建立自己的公司网站?  如何用AWS免费套餐快速搭建高效网站?  ,想在网上投简历,哪几个网站比较好?  开源网站制作软件,开源网站什么意思?  如何在宝塔面板中修改默认建站目录?  如何制作算命网站,怎么注册算命网站?  如何高效搭建专业期货交易平台网站?  如何获取开源自助建站系统免费下载链接?  实例解析angularjs的filter过滤器  如何在阿里云完成域名注册与建站?  佛山网站制作系统,佛山企业变更地址网上办理步骤?  广州网站建站公司选择指南:建站流程与SEO优化关键词解析  公司网站建设制作费用,想建设一个属于自己的企业网站,该如何去做?  建站之星如何一键生成手机站?  网站插件制作软件免费下载,网页视频怎么下到本地插件?  头像制作网站在线观看,除了站酷,还有哪些比较好的设计网站?  如何彻底卸载建站之星软件?  如何在VPS电脑上快速搭建网站?  完全自定义免费建站平台:主题模板在线生成一站式服务  清单制作人网站有哪些,近日“兴风作浪的姑奶奶”引起很多人的关注这是什么事情?  建站之星24小时客服电话如何获取?  香港服务器网站推广:SEO优化与外贸独立站搭建策略  潮流网站制作头像软件下载,适合母子的网名有哪些?  成都网站制作价格表,现在成都广电的单独网络宽带有多少的,资费是什么情况呢?  如何快速上传建站程序避免常见错误?  再谈Python中的字符串与字符编码(推荐)  建站为何优先选择香港服务器?  齐河建站公司:营销型网站建设与SEO优化双核驱动策略  韩国代理服务器如何选?解析IP设置技巧与跨境访问优化指南  建站之星如何配置系统实现高效建站?  网站按钮制作软件,如何实现网页中按钮的自动点击? 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。