Spring Security 基础

1. 初步使用

  • (1). 在 pom.xml 中添加 spring security 依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
1
2
3
4
  • (2). 创建继承 WebSecurityConfigurerAdapter 的类,并做一些基本配置
@EnableWebSecurity
public class WebSecurityConf extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().authenticated()
            .and()
            .formLogin(); //系统生成一个默认的登陆页面
    }
}
1
2
3
4
5
6
7
8
9
10
  • (3). 使用默认用户名 user 和启动过程中生成的一次性密码登陆。
Using generated security password: 307e932e-a39f-432e-a0c7-0326bd742e0a
1

参考:https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-security.html

  • (4). 配置文件中设置默认用户名/密码
spring.security.user.name=user # Default user name.
spring.security.user.password= # Password for the default user name.
1
2

引自 Spring Boot application.properties官方文档

2. 临时用户登陆

@Configuration
@EnableWebSecurity
public class WebSecurityConf extends WebSecurityConfigurerAdapter {

    @Autowired
    private BCryptPasswordEncoder passwordEncoder;

    @Bean
    public BCryptPasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .anyRequest().authenticated()
            .and()
            .formLogin();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .passwordEncoder(passwordEncoder)
                .withUser("user1").password(passwordEncoder.encode("123456")).roles("USER")
                .and()
                .withUser("user2").password(passwordEncoder.encode("123456")).roles("USER", "ADMIN");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

3. 数据库用户登陆

(1). 配置 WebSecurity

  • 这里只需要引入接口 UserDetailsService 的实现类即可。

  • 将实现类(例如 UserDetailsServiceImpl)引入,并如下配置:

@Configuration
@EnableWebSecurity
public class WebSecurityConf extends WebSecurityConfigurerAdapter {

    @Autowired
    private BCryptPasswordEncoder passwordEncoder;

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService)
            .passwordEncoder(passwordEncoder);
    }

    //......
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

(2). 实现 UserDetailsService 接口

  • 只简单实现,未任何深度处理
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    @Autowired
    private UserRepository userRepository;

    @Autowired
    private AuthorityRepository authorityRepository;

    public UserDetails loadUserByUsername(String username){
        User user = userRepository.findByUsername(username);
        List<Authority> authorities = authorityRepository.findByUsername(username);

        UserDetails userDetails = new UserDetailsImpl(user, authorities);

        return userDetails;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

(3). 需要实现 UserDetails 接口

  • Spring Security 提供了一个范例:org.springframework.security.core.userdetails.User

  • 最简单实现:

public class UserDetailsImpl implements UserDetails {
    private String username;
    private String password;
    private boolean accountNonExpired;
    private boolean accountNonLocked;
    private boolean credentialsNonExpired;
    private boolean enabled;
    private Set<GrantedAuthority> authorities;

    public UserDetailsImpl(User user, Collection<Authority> authorities){
        this.username = user.getUsername();
        this.password = user.getPassword();
        this.accountNonExpired = true;
        this.accountNonLocked = true;
        this.credentialsNonExpired = true;
        this.enabled = true;
        this.authorities = new HashSet<>();

        if (authorities != null){
            for (Authority a: authorities){
                this.authorities.add(new GrantedAuthorityImpl(a));
            }
        }
    }

    // Getters or Setters
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

(4). 需要实现 GrantedAuthority 接口

public class GrantedAuthorityImpl implements GrantedAuthority {
    private String authority;

    public GrantedAuthorityImpl(Authority authority){
        this.authority = authority.getAuthority();
    }

    @Override
    public String getAuthority() {
        return authority;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

(5). 需要创建 User, Authority 及相应的 JPA Repository

@Entity
@Table(name = "usr")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    private String username;

    private String password;

    private Boolean enabled;
    
    //...
}

public interface UserRepository extends JpaRepository<User, Long> {
    User findByUsername(String username);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Entity
@Table(name = "authority")
public class Authority {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    private String username;

    private String authority;

    //...
}

//...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

小贴士

从最后一条反向操作以上步骤,即可。

4. HttpScurity

@Configuration
@EnableWebSecurity
public class WebSecurityConf extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
             .authorizeRequests()
                .antMatchers("/help/**").permitAll()
                .anyRequest().authenticated()
                .and()
             .formLogin();
    }
1
2
3
4
5
6
7
8
9
10
11
12

(1). Ant 风格 URL

通配符 说明
? 任何单字符
* 0 - n 个任意数量的文件名字符(非目录)
** 0 - n 个任意层次的目录
最近更新: 8/5/2019, 10:43:50 PM