【Spring】五,Spring Security的基本使用

Spring Security的基本使用

添加依赖

将 spring-boot-starter-security 依赖添加到构建文件中

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

当应用启动的时候,自动配置功能会探测到Spring Security出现在了类路径中,因此它会初始化一些基本的安全配置。
此时,访问接口,会要求进行认证
在这里插入图片描述
用户名为:user,密码可以在应用的启动日志中找到

Using generated security password: 6b736fda-e3bb-4085-a191-6794624ff9e5

配置Spring Security

编写配置类

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
}

Spring Security为配置用户存储提供了多个可选方案:

  • 基于内存的用户存储;
  • 基于JDBC的用户存储;
  • 以LDAP作为后端的用户存储;
  • 自定义用户详情服务。

Spring Security为PasswordEncoder接口提供了多个实现:

  • BCryptPasswordEncoder:使用bcrypt强哈希加密。
  • NoOpPasswordEncoder:不进行任何转码。
  • Pbkdf2PasswordEncoder:使用PBKDF2加密。
  • SCryptPasswordEncoder:使用scrypt哈希加密。
  • StandardPasswordEncoder:使用SHA-256哈希加密。

自定义用户认证

定义用户实体
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Data
@Entity
@Table(name = "sys_user")
public class SysUser implements UserDetails {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "user_id")
    private long userId;

    @Column(name = "user_name")
    private String userName;

    @Column(name = "gender")
    private String gender;

    @Column(name = "account",unique = true,nullable = false)
    private String account;

    @Column(name = "password",nullable = false)
    private String password;

    @Column(name = "city")
    private String city;

    @Column(name = "created_by")
    private String createdBy;

    @Column(name = "created_time")
    private Date createdTime;

    @Column(name = "updated_by")
    private String updatedBy;

    @Column(name = "updated_time")
    private Date updatedTime;

    @JsonIgnoreProperties("users")
    @ManyToMany(targetEntity = SysRole.class)
    @JoinTable(name = "sys_user_role",
            joinColumns = @JoinColumn(name = "user_id",referencedColumnName = "user_id"),
            inverseJoinColumns = @JoinColumn(name = "role_id",referencedColumnName = "role_id"))
    private List<SysRole> roles;

    @PrePersist
    void createdTime(){
        this.createdTime = new Date();
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return Arrays.asList(new SimpleGrantedAuthority("ROLE_SYS_ADMIN"));
    }

    @Override
    public String getUsername() {
        return this.account;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}

User类实现了Spring Security的UserDetails接口。

通过实现UserDetails接口,我们能够提供更多信息给框架,比如用户都被授予了哪些权限以及用户的账号是否可用。

getAuthorities()方法应该返回用户被授予权限的一个集合。各种is…Expired()方法要返回一个boolean值,表明用户的账号是否可用或过期。

创建查询用户的Repository
public interface UserRepository extends CrudRepository<SysUser,Long> {
    SysUser findByAccount(String account);
}
创建控制器
/**
 * 用户相关操作
 */
@Slf4j
@Controller
@RequestMapping("/user")
public class UserController {

    private UserRepository userRepository;
    private PasswordEncoder passwordEncoder;

    @Autowired
    public UserController(UserRepository userRepository,PasswordEncoder passwordEncoder) {
        this.userRepository = userRepository;
        this.passwordEncoder = passwordEncoder;
    }

    @GetMapping("/getUserList")
    @ResponseBody
    public List<SysUser> getUserList(@AuthenticationPrincipal SysUser sysUser){
        log.info("当前登录用户为:" + sysUser.getUsername() );
        Iterable<SysUser> all = userRepository.findAll();
        List<SysUser> userList = new ArrayList<>();
        all.forEach(u -> userList.add(u));
        return userList;
    }

    @GetMapping("/getUserByAccount")
    @ResponseBody
    public SysUser getUserByAccount(@RequestParam("account") String account){
        SysUser sysUser = userRepository.findByAccount(account);
        return sysUser;
    }

}
创建用户详情服务

Spring Security的UserDetailsService是一个相当简单直接的接口:

public interface UserDetailsService {
  UserDetails loadUserByUsername(String username)
                     throws UsernameNotFoundException;
}

这个接口的实现会得到一个用户的用户名,并且要么返回查找到的 UserDetails 对象,要么在根据用户名无法得到任何结果的情况下抛出 Username NotFoundException。

@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private UserRepository userRepository;

    @Override
    public UserDetails loadUserByUsername(String account) throws UsernameNotFoundException {
        SysUser sysUser = userRepository.findByAccount(account);
        if (sysUser != null){
            return sysUser;
        }
        throw new UsernameNotFoundException("User account:'"+account+"' not found");
    }

}

将这个自定义的用户详情服务与Spring Security配置在一起,并且配置一些安全规则

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

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

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

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
            .authorizeRequests()
                .antMatchers("/system/register")
                .permitAll()
                .antMatchers("/user/**","/role/**")
                .hasRole("SYS_ADMIN")
                .and()
                .formLogin()
                .loginProcessingUrl("/login");

    }
}

/system/register:允许所有人访问。
/user/** /role/**:只有具备SYS_ADMIN角色的用户才能访问。

测试开始之前,需要在数据库中配置一个角色
在这里插入图片描述
在声明请求路径的安全需求时,hasRole()和permitAll()只是众多方法中的两个
在这里插入图片描述

了解用户是谁

我们有多种方式确定用户是谁,常用的方式如下:

  • 注入Principal对象到控制器方法中;
  • 注入Authentication对象到控制器方法中;
  • 使用SecurityContextHolder来获取安全上下文;
  • 使用@AuthenticationPrincipal注解来标注方法。
    在这里插入图片描述

完整的工程源码请访问:boot-integrate-security

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值