Spring Boot中使用 Spring Security 构建权限系统的示例代码
SpringSecurity是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。
权限控制是非常常见的功能,在各种后台管理里权限控制更是重中之重.在SpringBoot中使用SpringSecurity构建权限系统是非常轻松和简单的.下面我们就来快速入门SpringSecurity.在开始前我们需要一对多关系的用户角色类,一个restful的controller.
参考项目代码地址
-添加SpringSecurity依赖
首先我默认大家都已经了解SpringBoot了,在SpringBoot项目中添加依赖是非常简单的.把对应的spring-boot-starter-***加到pom.xml文件中就行了
org.springframework.boot spring-boot-starter-security
-配置SpringSecurity
简单的使用SpringSecurity只要配置三个类就完成了,分别是:
UserDetails
这个接口中规定了用户的几个必须要有的方法
publicinterfaceUserDetailsextendsSerializable{
//返回分配给用户的角色列表
CollectiongetAuthorities();
//返回密码
StringgetPassword();
//返回帐号
StringgetUsername();
//账户是否未过期
booleanisAccountNonExpired();
//账户是否未锁定
booleanisAccountNonLocked();
//密码是否未过期
booleanisCredentialsNonExpired();
//账户是否激活
booleanisEnabled();
}
UserDetailsService
这个接口只有一个方法loadUserByUsername,是提供一种用用户名查询用户并返回的方法。
publicinterfaceUserDetailsService{
UserDetailsloadUserByUsername(Stringvar1)throwsUsernameNotFoundException;
}
WebSecurityConfigurerAdapter
这个内容很多,就不贴代码了,大家可以自己去看.
我们创建三个类分别继承上述三个接口
此User类不是我们的数据库里的用户类,是用来安全服务的.
/**
*CreatedbyYuiconon2017/5/14.
*/
publicclassUserimplementsUserDetails{
privatefinalStringid;
//帐号,这里是我数据库里的字段
privatefinalStringaccount;
//密码
privatefinalStringpassword;
//角色集合
privatefinalCollectionauthorities;
User(Stringid,Stringaccount,Stringpassword,Collectionauthorities){
this.id=id;
this.account=account;
this.password=password;
this.authorities=authorities;
}
//返回分配给用户的角色列表
@Override
publicCollectiongetAuthorities(){
returnauthorities;
}
@JsonIgnore
publicStringgetId(){
returnid;
}
@JsonIgnore
@Override
publicStringgetPassword(){
returnpassword;
}
//虽然我数据库里的字段是`account`,这里还是要写成`getUsername()`,因为是继承的接口
@Override
publicStringgetUsername(){
returnaccount;
}
//账户是否未过期
@JsonIgnore
@Override
publicbooleanisAccountNonExpired(){
returntrue;
}
//账户是否未锁定
@JsonIgnore
@Override
publicbooleanisAccountNonLocked(){
returntrue;
}
//密码是否未过期
@JsonIgnore
@Override
publicbooleanisCredentialsNonExpired(){
returntrue;
}
//账户是否激活
@JsonIgnore
@Override
publicbooleanisEnabled(){
returntrue;
}
}
继承UserDetailsService
/**
*CreatedbyYuiconon2017/5/14.
*/
@Service
publicclassUserDetailsServiceImplimplementsUserDetailsService{
//jpa
@Autowired
privateUserRepositoryuserRepository;
/**
*提供一种从用户名可以查到用户并返回的方法
*@paramaccount帐号
*@returnUserDetails
*@throwsUsernameNotFoundException
*/
@Override
publicUserDetailsloadUserByUsername(Stringaccount)throwsUsernameNotFoundException{
//这里是数据库里的用户类
Useruser=userRepository.findByAccount(account);
if(user==null){
thrownewUsernameNotFoundException(String.format("没有该用户'%s'.",account));
}else{
//这里返回上面继承了UserDetails接口的用户类,为了简单我们写个工厂类
returnUserFactory.create(user);
}
}
}
UserDetails工厂类
/**
*CreatedbyYuiconon2017/5/14.
*/
finalclassUserFactory{
privateUserFactory(){
}
staticUsercreate(Useruser){
returnnewUser(
user.getId(),
user.getAccount(),
user.getPassword(),
mapToGrantedAuthorities(user.getRoles().stream().map(Role::getName).collect(Collectors.toList()))
);
}
//将与用户类一对多的角色类的名称集合转换为GrantedAuthority集合
privatestaticListmapToGrantedAuthorities(Listauthorities){
returnauthorities.stream()
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
}
}
重点,继承WebSecurityConfigurerAdapter类
/**
*CreatedbyYuiconon2017/5/14.
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
publicclassWebSecurityConfigextendsWebSecurityConfigurerAdapter{
//Spring会自动寻找实现接口的类注入,会找到我们的UserDetailsServiceImpl类
@Autowired
privateUserDetailsServiceuserDetailsService;
@Autowired
publicvoidconfigureAuthentication(AuthenticationManagerBuilderauthenticationManagerBuilder)throwsException{
authenticationManagerBuilder
//设置UserDetailsService
.userDetailsService(this.userDetailsService)
//使用BCrypt进行密码的hash
.passwordEncoder(passwordEncoder());
}
//装载BCrypt密码编码器
@Bean
publicPasswordEncoderpasswordEncoder(){
returnnewBCryptPasswordEncoder();
}
//允许跨域
@Bean
publicWebMvcConfigurercorsConfigurer(){
returnnewWebMvcConfigurerAdapter(){
@Override
publicvoidaddCorsMappings(CorsRegistryregistry){
registry.addMapping("/**").allowedOrigins("*")
.allowedMethods("GET","HEAD","POST","PUT","DELETE","OPTIONS")
.allowCredentials(false).maxAge(3600);
}
};
}
@Override
protectedvoidconfigure(HttpSecurityhttpSecurity)throwsException{
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的restapi要允许匿名访问
.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权限的用户可以访问
publicclassUserController{
@Autowired
privateUserRepositoryrepository;
@PreAuthorize("hasRole('ADMIN')")//有ROLE_ADMIN权限的用户可以访问
@RequestMapping(method=RequestMethod.GET)
publicListgetUsers(){
returnrepository.findAll();
}
}
-结语
SpringBoot中SpringSecurity的入门非常简单,很快我们就能有一个满足大部分需求的权限系统了.而配合SpringSecurity的好搭档就是JWT了,两者的集成文章网络上也很多,大家可以自行集成.因为篇幅原因有不少代码省略了,需要的可以参考项目代码
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。