美文网首页程序员
说说如何使用 Spring Security 自定义账户权限体系

说说如何使用 Spring Security 自定义账户权限体系

作者: deniro | 来源:发表于2020-10-07 09:25 被阅读0次

如果使用之前说过的基于 JDBC 的认证方案,那么必须遵循一定的规范,比如字段名名称限制等等。所以如果需要完全自定义,我们可以使用直接 Spring Data Repository。

Craig Walls 举了这样一个示例,来说明如何自定义账户权限体系。

1 定义账户实体类

@Entity
@Data
@NoArgsConstructor(access = AccessLevel.PRIVATE, force = true)
@RequiredArgsConstructor
public class User implements UserDetails {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private final String username;
    private final String password;
    private final String fullname;
    private final String street;
    private final String city;
    private final String state;
    private final String zip;
    private final String phoneNumber;


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

    @Override
    public String getPassword() {
        return null;
    }

    @Override
    public String getUsername() {
        return null;
    }

    @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 接口。该接口定义一些与权限有关的方法。

方法名 说明
getAuthorities 返回该账户被授予的权限集合
isAccountNonExpired 账户是否未过期
isAccountNonLocked 账户是否未被锁定
isCredentialsNonExpired 账户凭证是否未过期
isEnabled 账户是否可用

示例代码中,以上这些方法全部返回 TRUE,即允许该账户登录使用。

2 账户 Repository 接口

public interface UserRepository extends CrudRepository<User,Long> {

    User findByUsername(String username);
}

Spring Data JPA 会在运行时自动生成账户 Repository 接口的实现类。这种方式的好处是不需要写代码。

3 账户 Service 接口

Spring Security 本身定义了 UserDetailsService 接口,代码如下:

public interface UserDetailsService {

    UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}

Service接口中定义了一个依据账号名获取账号的方法。如果找不到相应账号,就会抛出 UsernameNotFoundException 异常。

UserDetailsService 是Spring Security 定义的接口。

定义 UserDetailsService 的实现类:

@Service
public class UserRepositoryUserDetailsService implements UserDetailsService {

    private UserRepository userRepository;

    @Autowired
    public UserRepositoryUserDetailsService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }


    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userRepository.findByUsername(username);
        if (user != null) {
            return user;
        } else {
            throw new UsernameNotFoundException("User '" + username + "' not found");
        }
    }
}

UserDetailsService 的实现类通过构造器方式将UserRepository 注入进来。然后在 loadUserByUsername 方法中通过 UserRepository 的 findByUsername 方法来查询账户对象。
UserDetailsService 的实现类使用了 @Service 注解,这样 Spring 应用启动时,就会将其初始化为一个 bean。

接下来需要把 UserDetailsService 服务与 Spring Security 绑定起来。在 SecurityConfig 类中,注入并绑定UserDetailsService 服务:
  @Autowired
  UserDetailsService userDetailsService;

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

与 JDBC 方式一样,我们也可以配置密码编码器,这样存放在数据库中的密码就是密文的。

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

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

首先定义一个返回 PasswordEncoder 对象的方法,然后调用passwordEncoder() 方法,该方法的入参是PasswordEncoder 对象,这样 AuthenticationManagerBuilder 对象就装配上了密码编码器。

因为encoder() 方法定义了 @Bean 注解,所以对encoder() 方法的调用都会被 Spring 拦截,接着 Spring 框架会返回应用上下文中的 PasswordEncoder bean 实例。


通过以上方式,我们就可以实现自定义 Spring Security 权限体系。

相关文章

网友评论

    本文标题:说说如何使用 Spring Security 自定义账户权限体系

    本文链接:https://www.haomeiwen.com/subject/onfduktx.html