使用Spring Security进行权限验证
Posted 天码营
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用Spring Security进行权限验证相关的知识,希望对你有一定的参考价值。
使用Spring Security进行权限验证 由Cliff发表在天码营
Spring Security,这是一种基于Spring AOP和Servlet过滤器的安全框架。它提供全面的安全性解决方案,同时在Web请求级和方法调用级处理身份确认和授权。在Spring Framework基础上,Spring Security充分利用了依赖注入(DI,Dependency Injection)和面向切面技术。今天我们就来学习一下如何利用Spring security方便的进行权限验证。
添加依赖
首先还是先定义我们所需要的依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
在本次学习中,我们仍然使用Spring Boot作为框架,同时引入我们的核心学习库:spring-boot-starter-security
。模板引擎仍然选用我们熟悉的thymeleaf。最后使用了Spring Data Jpa+ hsqldb作为数据库。
系统设计
本次学习,我们将实现一个简单的有权限验证的系统,在权限验证上,我们还可以加上一个简单的用户角色判断的验证,这样,我们就有以下几个页面:
- 首页 所有人可访问
- 登录页 所有人可访问
- 普通页 登录后的用户都可访问
- 管理页 管理员可访问
- 无权限提醒页 当一个用户访问了其没有权限的页面,需要有一个页面来对其进行提醒
页面确定后,我们来看看用户表需要哪些字段。为了简化处理,我们的用户表只需要用户名、密码以及一个角色字段来确定其身份即可。
这样,我们的简单系统设计就出来了,为了加深印象,我们先不管权限验证相关代码,我们先来实现整个简单的系统吧。
系统实现
数据访问层
首先我们需要一个数据层以及业务层为我们的业务逻辑提供支持,由于我们没有业务逻辑,业务逻辑层就省去了,只需要利用Spring Data JPA来实现一个简单数据访问层即可。
首先来定义一个User对象,设置用户名、密码、角色三个字段:
@Entity
public class User
@Enumerated(EnumType.STRING)
private ROLE role;
@Id
private String username;
private String password;
...
然后定义UserRepository:
public interface UserRepository extends JpaRepository<User, Integer>
User findByUsername(String username);
这样,数据访问层就实现好了。
展现层
在展现层,我们需要提供系统设计中的所有页面。Controller
代码如下:
@Controller
public class HomeController
@RequestMapping(value = "", "/home", method=RequestMethod.GET)
public String home()
return "home";
@RequestMapping(value = "/helloadmin", method=RequestMethod.GET)
public String helloAdmin()
return "helloAdmin";
@RequestMapping(value = "/hellouser", method=RequestMethod.GET)
public String helloUser()
return "helloUser";
@RequestMapping(value = "/login", method=RequestMethod.GET)
public String login()
return "login";
@RequestMapping("/403")
public String forbidden()
return "403";
注:其中返回的页面在src/main/resources/templates
下,都是最简单的html页面,这里不在赘述。
大家可以看到,最后一个403页面实际上应该是当用户访问了没有权限的页面后显示的页面,因此在这里我们需要设置:当发现请求的返回码是403
时,需要交给'/403'进行处理。
@Configuration
public class ErrorPageConfig
@Bean
public EmbeddedServletContainerCustomizer embeddedServletContainerCustomizer()
return new MyCustomizer();
private static class MyCustomizer implements EmbeddedServletContainerCustomizer
@Override
public void customize(ConfigurableEmbeddedServletContainer container)
container.addErrorPages(new ErrorPage(HttpStatus.FORBIDDEN, "/403"));
这里我们利用了Spring自带的EmbeddedServletContainerCustomizer进行设置。当Spring发现有类型为EmbeddedServletContainerCustomizer注册进来,便会调用EmbeddedServletContainerCustomizer的customize方法,此时,我们可以对整个Container进行设置,这里,我们添加了对于返回值为HttpStatus.FORBIDDEN
的请求,将其交给/403
进行处理。
启动程序
当然,我们还需要添加一个系统的启动函数,这个大家都应该很熟悉了,没有用过Spring Boot的同学可以参考教材Spring Boot应用开发。
@SpringBootApplication
public class App
public static void main( String[] args )
SpringApplication.run(App.class, args);
初始化数据
最后,让我们准备一些测试数据:
@Service
public class DataInit
@Autowired UserRepository userRepository;
@PostConstruct
public void dataInit()
User admin = new User();
admin.setPassword("admin");
admin.setUsername("admin");
admin.setRole(User.ROLE.admin);
userRepository.save(admin);
User user = new User();
user.setPassword("user");
user.setUsername("user");
user.setRole(User.ROLE.user);
userRepository.save(user);
现在,一切准备就绪,进入根目录,运行mvn spring-boot:run
,访问以下网页即可:
- http://localhost:8080/
- http://localhost:8080/login
- http://localhost:8080/hellouser
- http://localhost:8080/helloadmin
- http://localhost:8080/403
添加权限验证
上节内容我们搭建了一个简单的网页应用,但是其中完全没有任何登录、登出、权限验证等等的处理,只能保证每个页面的简单访问。接下来我们就来用Spring Security添加这些功能。
添加Spring Security配置
我们首先使用Spring Security帮我们做登录、登出的处理,以及当用户未登录时只能访问http://localhost:8080/
以及http://localhost:8080/login
两个页面。
从数据库中获取用户信息的操作是必不可少的,我们首先来实现UserDetailsService,这个接口需要我们实现一个方法:loadUserByUsername
。即通过用户名加载与该用户的用户名、密码以及权限相关的信息。
public class CustomUserDetailsService implements UserDetailsService
@Autowired UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
User user = userRepository.findByUsername(username);
if(user == null)
throw new UsernameNotFoundException("not found");
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority(user.getRole().name()));
System.err.println("username is " + username + ", " + user.getRole().name());
return new org.springframework.security.core.userdetails.User(user.getUsername(),
user.getPassword(), authorities);
然后我们添加一个SecurityConfig类来对Security进行配置,使AuthenticationManager
使用我们的CustomUserDetailsService
来获取用户信息:
@Configuration
@EnableWebMvcSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter
@Override
@Bean
public UserDetailsService userDetailsService()
return new CustomUserDetailsService();
@Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception
auth.userDetailsService(userDetailsService());
@Override
protected void configure(HttpSecurity http) throws Exception
http
.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/helloadmin")
.permitAll()
.and()
.logout()
.permitAll();
我们可以看到,SecurityConfig
上添加了@EnableWebMvcSecurity
标注,使得Spring Security提供并且支持了Spring MVC的集成。
同时,SecurityConfig
还继承了WebSecurityConfigurerAdapter
类,并覆盖了其中的几个方法:
- userDetailsService()将我们自定义的
CustomUserDetailsService
实例化并添加进security的上下文当中 - configure(AuthenticationManagerBuilder auth) 在该方法中,我们使AuthenticationManager使用
CustomUserDetailsService
作为其UserDetailsService
实例。 - configure(HttpSecurity http) 对URL进行权限配置,使得"/", "/home"不需要登录就可以访问,其他需要登录。登录的地址是'/login',当登录成功后将跳转到
/helloadmin
页面,并且登录、登出页面都是不需要登录就可以访问的。
这时候重启我们的应用,再次访问http://localhost:8080/hellouser
,你会发现网页会自动跳转到登录页面,同时,我们的登录、登出功能已经实现好了。
实现一个UserDetailsService
,再对Spring Security进行配置,这样,登录、登出以及登录的验证功能就可以实现啦,怎么样,是不是特别的简单。
添加角色验证
之前系统设计时,我们将用户分成了管理员与普通用户,那么,如何将这两类用户访问的页面分开,使得普通用户看不见管理员相关的页面呢?很简单,我们可以通过两行标注来实现这个功能,修改HomeController
:
@RequestMapping(value = "/helloadmin", method=RequestMethod.GET)
@PreAuthorize("hasAnyRole('admin')")
public String helloAdmin()
return "helloAdmin";
@RequestMapping(value = "/hellouser", method=RequestMethod.GET)
@PreAuthorize("hasAnyRole('admin', 'user')")
public String helloUser()
return "helloUser";
修改helloAdmin
和helloUser
方法,添加@PreAuthorize
标注,当我们访问这两个URL的时候,Spring Security会帮我们验证当前用户是否有权限访问该地址。
现在重新启动服务,用user账号登陆,访问'http://localhost:8080/helloadmin',怎么样,是不是看见403页面啦。添加角色控制,就是这么简单。
更多文章请访问天码营网站
以上是关于使用Spring Security进行权限验证的主要内容,如果未能解决你的问题,请参考以下文章
通过 Spring security ldap 对用户进行身份验证时未授予任何权限错误
Spring Security框架下Restful Token的验证方案