温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Spring如何配置自定义的用户存储

发布时间:2022-10-18 16:05:13 来源:亿速云 阅读:122 作者:iii 栏目:编程语言

这篇文章主要讲解了“Spring如何配置自定义的用户存储”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Spring如何配置自定义的用户存储”吧!

配置自定义的用户存储

通过查看AuthenticationManagerBuilder的源码可以发现里面还有一个方法 userDetailsService(),允许我们自定义用户存储的实现.如下

/**
     * Add authentication based upon the custom {@link UserDetailsService} that is passed
     * in. It then returns a {@link DaoAuthenticationConfigurer} to allow customization of
     * the authentication.
     *
     * <p>
     * This method also ensure that the {@link UserDetailsService} is available for the
     * {@link #getDefaultUserDetailsService()} method. Note that additional
     * {@link UserDetailsService}'s may override this {@link UserDetailsService} as the
     * default.
     * </p>
     *
     * @return a {@link DaoAuthenticationConfigurer} to allow customization of the DAO
     * authentication
     * @throws
    public <T extends UserDetailsService> DaoAuthenticationConfigurer<AuthenticationManagerBuilder, T> userDetailsService(
            T userDetailsService) throws Exception {
        this.defaultUserDetailsService = userDetailsService;
        return apply(new

我们发现 此方法接收一个 UserDetailsService 的实现类.我们可以再点进去查看一下 UserDetailsService 的源码,如下:

/**
 * Core interface which loads user-specific data.
 * <p>
 * It is used throughout the framework as a user DAO and is the strategy used by the
 * {@link org.springframework.security.authentication.dao.DaoAuthenticationProvider
 * DaoAuthenticationProvider}.
 *
 * <p>
 * The interface requires only one read-only method, which simplifies support for new
 * data-access strategies.
 *
 * @see org.springframework.security.authentication.dao.DaoAuthenticationProvider
 * @see UserDetails
 *
 * @author
public interface UserDetailsService
    // ~ Methods
    // ========================================================================================================

    /**
     * Locates the user based on the username. In the actual implementation, the search
     * may possibly be case sensitive, or case insensitive depending on how the
     * implementation instance is configured. In this case, the <code>UserDetails</code>
     * object that comes back may have a username that is of a different case than what
     * was actually requested..
     *
     * @param username the username identifying the user whose data is required.
     *
     * @return a fully populated user record (never <code>null</code>)
     *
     * @throws
    UserDetails loadUserByUsername(String username) throws

发现这是一个接口,并且只有一个方法 loadUserByUsername(),我们所需要做的就是实现loadUserByUsername()方法,根据给定的用户名来查找用户。
loadUserByUsername()方法会返回代表给定用户的UserDetails对象.

而这个UserDetail 又是个什么呢?我们再次产看其源码,如下:

/**
 * Provides core user information.
 *
 * <p>
 * Implementations are not used directly by Spring Security for security purposes. They
 * simply store user information which is later encapsulated into {@link Authentication}
 * objects. This allows non-security related user information (such as email addresses,
 * telephone numbers etc) to be stored in a convenient location.
 * <p>
 * Concrete implementations must take particular care to ensure the non-null contract
 * detailed for each method is enforced. See
 * {@link org.springframework.security.core.userdetails.User} for a reference
 * implementation (which you might like to extend or use in your code).
 *
 * @see UserDetailsService
 * @see UserCache
 *
 * @author
public interface UserDetails extends Serializable
    // ~ Methods
    // ========================================================================================================

    /**
     * Returns the authorities granted to the user. Cannot return <code>null</code>.
     *
     * @return
    Collection<? extends GrantedAuthority> getAuthorities();

    /**
     * Returns the password used to authenticate the user.
     *
     * @return
    String getPassword();

    /**
     * Returns the username used to authenticate the user. Cannot return <code>null</code>
     * .
     *
     * @return
    String getUsername();

    /**
     * Indicates whether the user's account has expired. An expired account cannot be
     * authenticated.
     *
     * @return
    boolean isAccountNonExpired();

    /**
     * Indicates whether the user is locked or unlocked. A locked user cannot be
     * authenticated.
     *
     * @return
    boolean isAccountNonLocked();

    /**
     * Indicates whether the user's credentials (password) has expired. Expired
     * credentials prevent authentication.
     *
     * @return
    boolean isCredentialsNonExpired();

    /**
     * Indicates whether the user is enabled or disabled. A disabled user cannot be
     * authenticated.
     *
     * @return
    boolean

发现这也是一个接口,也就是说我们还要实现这个 UserDetail接口.这个结构封装了用户的登陆信息.

好了,了解了 userDetailsService 方法的构造,我们就可以着手写代码了.

首先定义一个 MyUserService 实现 UserDetailsService 接口.并在重写的 loadUserByUsername 方法中返回 UserDetail类型的对象即可,
代码如下:

/**
 * 自定义用户实现
 *
 * @author itguang
 * @create
public class MyUserService implements UserDetailsService


    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {



        //自定义用户存储数据来源,可以是从关系型数据库,非关系性数据库,或者其他地方获取用户数据。
        UserEntity userEntity = new UserEntity("itguang", "123456", true);

        //还可以在此设置账号的锁定,过期,凭据失效 等参数
        //...

        // 设置 权限,可以是从数据库中查找出来的
        ArrayList<GrantedAuthority> authorities = new ArrayList<>();
        authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
        authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));


        userEntity.setAuthorities(authorities);

        return

可以看到我们最后返回了一个 UserEntity 对象,这个类是我们自定义的 对UserDetail接口的实现类,代码如下:

/**
 * @author itguang
 * @create

@Data
public class UserEntity implements UserDetails{


    /**
     * 用户名
     */
    private String username;

    /**
     * 密码
     */
    private String password;

    /**
     * 是否可用
     */
    private Boolean enabled;

    /**
     *用户所拥有的权限
     */
    private List<? extends GrantedAuthority> authorities;

    /**
     * 用户的账号是否过期,过期的账号无法通过授权验证. true 账号未过期
     */
    private Boolean accountNonExpired = true;

    /**
     * 用户的账户是否被锁定,被锁定的账户无法通过授权验证. true 账号未锁定
     */
    private Boolean accountNonLocked = true;

    /**
     * 用户的凭据(pasword) 是否过期,过期的凭据不能通过验证. true 没有过期,false 已过期
     */
    private Boolean credentialsNonExpired = true;

    public UserEntity(String username, String password, Boolean enabled) {
        this.username = username;
        this.password = password;
        this.enabled = enabled;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return authorities;
    }

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

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

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

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

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

    @Override
    public boolean isEnabled() {
        return

为什么我们要这样写呢,其实莫慌,我们如果不像自己实现 UserDetails 接口,Spring Security 已经为我们实现好了.我们来到 UserDetails接口,
把鼠标放到 UserDetails 上,在idea下按 ctrl+h ,我们就可以看到这个接口的实现类,如图:

除了我们自定义的UserEntity外,还有一个 User,其实这就是Spring Security为我们实现好的 UserDetails 类.我们可以看到它的源码如下:

public class User implements UserDetails, CredentialsContainer

    private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;

    // ~ Instance fields
    // ================================================================================================
    private String password;
    private final String username;
    private final Set<GrantedAuthority> authorities;
    private final boolean accountNonExpired;
    private final boolean accountNonLocked;
    private final boolean credentialsNonExpired;
    private final boolean enabled;

    //...

由于源码太长,这里只贴出一部分,可以看到这里面也有我们在UserEntity定义的字段.其实也不奇怪了,本来我们的 UserEntity 就是按着User进行改造的嘛.

之所以自定义UserEntity,这里是为了方面初学者进行快速入门,相比于User我们的UserEntity还是很简单的.

现在 我们的 UserDetailsService 已经完成了,接下来就是在 SecurityConfig 的configure方法中使用了,如下:

/**
 * 自定义用户存储
 *
 * @author itguang
 * @create
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter


    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(new

怎么样是不是很简单.

测试.

最后进行测试,运行项目,访问: http://localhost/hello ,会跳转到 http://localhost/login 让我们登陆,我们是输入 用户名 itguang 和密码 123456

点击登录,就会看到浏览器返回一个 hello Spring Security ,说明我们自定义用户存储已经完美实现.

感谢各位的阅读,以上就是“Spring如何配置自定义的用户存储”的内容了,经过本文的学习后,相信大家对Spring如何配置自定义的用户存储这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI