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

网友投稿 199 2023-04-20


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文件中就行了

org.springframework.boot

spring-boot-starter-security

- 配置 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 SltgwuhzUtring 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 mapToGrantedAuthorities(List 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 getUsers() {

return repository.findAll();

}

}

- 结语

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


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:java去掉文本中多余的空格与空行实例代码
下一篇:Java游戏俄罗斯方块的实现实例
相关文章

 发表评论

暂时没有评论,来抢沙发吧~