security 介绍
Spring Security是能够为J2EE项目提供综合性的安全访问控制解决方案的安全框架。它依赖于Servlet过滤器。这些过滤器拦截进入请求,并且在应用程序处理该请求之前进行某些安全处理。
build.gradle 依赖文件
buildscript {
ext {
springBootVersion = '2.0.1.RELEASE'
}
repositories {
maven {
url 'http://maven.aliyun.com/nexus/content/groups/public'
}
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
maven {
url 'http://maven.aliyun.com/nexus/content/groups/public'
}
}
dependencies {
compile('org.springframework.boot:spring-boot-starter')
compile('org.springframework.boot:spring-boot-starter-data-jpa')
compile('org.springframework.boot:spring-boot-starter-security')
compile('mysql:mysql-connector-java:6.0.5')
testCompile('org.springframework.boot:spring-boot-starter-test')
}
application.properties
server.port=8080
debug=true
# DataSource
spring.datasource.url=jdbc:mysql://localhost:3306/test?characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# JPA
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
定义角色实体
@Entity
public class SysRole {
@Id
@GeneratedValue
private Long id;
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
定义用户POJO
我们在定义用户的时候需要实现UserDetails接口,这样我们的用户实体即为Spring Security所使用的用户,定义好用户之后,我们还要配置用户和角色之间的多对多关系,正常情况下,角色和权限是两回事,所以我们还需要重写getAuthorities方法,将用户的角色和权限关联起来
@Entity
public class SysUser implements UserDetails {
@Id
@GeneratedValue
private Long id;
private String username;
private String password;
@ManyToMany(cascade = {CascadeType.REFRESH},fetch = FetchType.EAGER)
private List<SysRole> roles;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
public List<SysRole> getRoles() {
return roles;
}
public void setRoles(List<SysRole> roles) {
this.roles = roles;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<GrantedAuthority> auths = new ArrayList<>();
List<SysRole> roles = this.getRoles();
for (SysRole role : roles) {
auths.add(new SimpleGrantedAuthority(role.getName()));
}
return auths;
}
@Override
public String getPassword() {
return this.password;
}
@Override
public String getUsername() {
return this.username;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
预设数据
我们先在表中定义好几个角色和用户,方便我们后边做测试用
insert into `sys_role`(`id`,`name`) values (1,'ROLE_ADMIN'),(2,'ROLE_USER');
insert into `sys_user`(`id`,`password`,`username`) values (1,'root','root'),(2,'sang','sang');
insert into `sys_user_roles`(`sys_user_id`,`roles_id`) values (1,1),(2,2);
创建数据访问接口
public interface SysUserRepository extends JpaRepository<SysUser, Long> {
SysUser findByUsername(String username);
}
自定义UserDetailsService
public class CustomUserService implements UserDetailsService {
@Autowired
SysUserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
SysUser user = userRepository.findByUsername(s);
if (user == null) {
throw new UsernameNotFoundException("用户名不存在");
}
System.out.println("s:"+s);
System.out.println("username:"+user.getUsername()+";password:"+user.getPassword());
return user;
}
}
首先这里我们需要重写UserDetailsService接口,然后实现该接口中的loadUserByUsername方法,通过该方法查询到对应的用户,这里之所以要实现UserDetailsService接口,是因为在Spring Security中我们配置相关参数需要UserDetailsService类型的数据
配置Spring Security
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
UserDetailsService customUserService() {
return new CustomUserService();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customUserService());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and().formLogin().loginPage("/login").failureUrl("/login?error").permitAll().and()
.logout().permitAll();
}
}
- 首先当我们要自定义Spring Security的时候我们需要继承自WebSecurityConfigurerAdapter来完成,相关配置重写对应 方法即可。
- 我们在这里注册CustomUserService的Bean,然后通过重写configure方法添加我们自定义的认证方式。
- 在configure(HttpSecurity http)方法中,我们设置了登录页面,而且登录页面任何人都可以访问,然后设置了登录失败地址,也设置了注销请求,注销请求也是任何人都可以访问的。
- permitAll表示该请求任何人都可以访问,.anyRequest().authenticated(),表示其他的请求都必须要有权限认证。
- 这里我们可以通过匹配器来匹配路径,比如antMatchers方法,假设我要管理员才可以访问admin文件夹下的内容,我可以这样来写:.antMatchers("/admin/").hasRole("ROLE_ADMIN"),也可以设置admin文件夹下的文件可以有多个角色来访问,写法如下:.antMatchers("/admin/").hasAnyRole("ROLE_ADMIN","ROLE_USER")
6.可以通过hasIpAddress来指定某一个ip可以访问该资源,假设只允许访问ip为210.210.210.210的请求获取admin下的资源,写法如下 .antMatchers("/admin/**").hasIpAddress("210.210.210.210")