首页 > 开发 > Java > 正文

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

2024-07-13 10:10:56
字体:
来源:转载
供稿:网友

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. */@Servicepublic 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 了,两者的集成文章网络上也很多,大家可以自行集成.因为篇幅原因有不少代码省略了,需要的可以参考项目代码

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持VeVb武林网。


注:相关教程知识阅读请移步到JAVA教程频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表