美文网首页程序员
说说如何使用 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