SpringSecurity自定义用户登录

Posted 城南少年与猫

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringSecurity自定义用户登录相关的知识,希望对你有一定的参考价值。

根据上一节的配置,默认在服务开启的时候会被要求自动的进行表单登陆。用到的用户名只能是一个固定的用户名user,它的密码是每次启动的时候服务器自动生成的。最常见的场景是我们的用户是从数据库中获取的。

1.处理用户信息获取逻辑

import org.slf4j.LoggerFactory;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import java.util.logging.Logger;
//自定义用户处理的逻辑
//用户的信息的service
@Component
public class MyUserDetailService implements UserDetailsService {
    /**
     * 日志处理类
     */
    private org.slf4j.Logger logger =  LoggerFactory.getLogger(this.getClass());
    /**
     * 根据用户名加载用户信息
     *
     * @param username 用户名
     * @return UserDetails
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        logger.info("表单登录用户名:" + username);
        System.out.println("表单登录用户名:" + username);
        return new User(username,"123456",true,
                true,
                true,
                true,
                AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
    }
}

这里我们用的security里面的User进行存放,但是我们这边存放的密码是明文"123456",接下来会报错(没有用它的加密):

技术分享图片

需要注意的是 在这里用了Spring默认的一个类User,在自己的实现过程中并不一定要用Spring的类
可以自己定义一个对象实现UserDetail接口。

public class User implements  UserDetails,CredentialsContrain{}

2.加密用户的登录

我们来修改下MyUserDetailService,如下:

import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

//自定义用户处理的逻辑
//用户的信息的service
@Component
public class MyUserDetailService implements UserDetailsService {
    /**
     * 日志处理类
     */
    private org.slf4j.Logger logger =  LoggerFactory.getLogger(this.getClass());
    @Autowired
    private PasswordEncoder passwordEncoder;
    /**
     * 根据用户名加载用户信息
     *
     * @param username 用户名
     * @return UserDetails
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        logger.info("表单登录用户名:" + username);
        System.out.println("表单登录用户名:" + username);
        List<GrantedAuthority> grantedAuthorityList = new ArrayList<>();
        grantedAuthorityList.add(new GrantedAuthority() {
            @Override
            public String getAuthority() {
                return "admin";
            }
        });

        String pWord =passwordEncoder.encode("123");
        System.out.println("表单登录密码:" + pWord);
        logger.info(pWord);
        return new User("test",pWord,true,
                true,
                true,
                true,
                AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
    }
}

启动 使用test:123 即可登录成功

3.放入自定义User对象

MyUser:

package urity.demo.support;

import org.springframework.security.core.CredentialsContainer;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.SpringSecurityCoreVersion;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.util.Assert;

import java.io.Serializable;
import java.util.*;
@Slf4j
public class MyUser implements UserDetails, CredentialsContainer {




        private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;

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

        // ~ Constructors
        // ===================================================================================================

        /**
         * Calls the more complex constructor with all boolean arguments set to {@code true}.
         */
        public MyUser(String username, String password,
                                 Collection<? extends GrantedAuthority> authorities) {
            this(username, password, true, true, true, true, authorities);
        }

        /**
         * Construct the <code>User</code> with the details required by
         * {@link org.springframework.security.authentication.dao.DaoAuthenticationProvider}.
         *
         * @param username the username presented to the
         * <code>DaoAuthenticationProvider</code>
         * @param password the password that should be presented to the
         * <code>DaoAuthenticationProvider</code>
         * @param enabled set to <code>true</code> if the user is enabled
         * @param accountNonExpired set to <code>true</code> if the account has not expired
         * @param credentialsNonExpired set to <code>true</code> if the credentials have not
         * expired
         * @param accountNonLocked set to <code>true</code> if the account is not locked
         * @param authorities the authorities that should be granted to the caller if they
         * presented the correct username and password and the user is enabled. Not null.
         *
         * @throws IllegalArgumentException if a <code>null</code> value was passed either as
         * a parameter or as an element in the <code>GrantedAuthority</code> collection
         */
        public MyUser(String username, String password, boolean enabled,
                                 boolean accountNonExpired, boolean credentialsNonExpired,
                                 boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) {

            if (((username == null) || "".equals(username)) || (password == null)) {
                throw new IllegalArgumentException(
                        "Cannot pass null or empty values to constructor");
            }

            this.username = username;
            this.password = password;
            this.enabled = enabled;
            this.accountNonExpired = accountNonExpired;
            this.credentialsNonExpired = credentialsNonExpired;
            this.accountNonLocked = accountNonLocked;
            this.authorities = Collections.unmodifiableSet(sortAuthorities(authorities));
        }


    public void setMyUserDetails(urity.demo.entity.User user){
        this.username = user.getUsername();
        this.password = user.getPassword();
    }
        // ~ Methods
        // ========================================================================================================

        public Collection<GrantedAuthority> getAuthorities() {
            return authorities;
        }

        public String getPassword() {
            return password;
        }

        public String getUsername() {
            return username;
        }

        public boolean isEnabled() {
            return enabled;
        }

        public boolean isAccountNonExpired() {
            return accountNonExpired;
        }

        public boolean isAccountNonLocked() {
            return accountNonLocked;
        }

        public boolean isCredentialsNonExpired() {
            return credentialsNonExpired;
        }

        public void eraseCredentials() {
            password = null;
        }

        private static SortedSet<GrantedAuthority> sortAuthorities(
                Collection<? extends GrantedAuthority> authorities) {
            Assert.notNull(authorities, "Cannot pass a null GrantedAuthority collection");
            // Ensure array iteration order is predictable (as per
            // UserDetails.getAuthorities() contract and SEC-717)
            SortedSet<GrantedAuthority> sortedAuthorities = new TreeSet<GrantedAuthority>(
                    new MyUser.AuthorityComparator());

            for (GrantedAuthority grantedAuthority : authorities) {
                Assert.notNull(grantedAuthority,
                        "GrantedAuthority list cannot contain any null elements");
                sortedAuthorities.add(grantedAuthority);
            }

            return sortedAuthorities;
        }

        private static class AuthorityComparator implements Comparator<GrantedAuthority>,
                Serializable {
            private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;

            public int compare(GrantedAuthority g1, GrantedAuthority g2) {
                // Neither should ever be null as each entry is checked before adding it to
                // the set.
                // If the authority is null, it is a custom authority and should precede
                // others.
                if (g2.getAuthority() == null) {
                    return -1;
                }

                if (g1.getAuthority() == null) {
                    return 1;
                }

                return g1.getAuthority().compareTo(g2.getAuthority());
            }
        }

        /**
         * Returns {@code true} if the supplied object is a {@code User} instance with the
         * same {@code username} value.
         * <p>
         * In other words, the objects are equal if they have the same username, representing
         * the same principal.
         */
        @Override
        public boolean equals(Object rhs) {
            if (rhs instanceof MyUser) {
                return username.equals(((MyUser) rhs).username);
            }
            return false;
        }

        /**
         * Returns the hashcode of the {@code username}.
         */
        @Override
        public int hashCode() {
            return username.hashCode();
        }

        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();
            sb.append(super.toString()).append(": ");
            sb.append("Username: ").append(this.username).append("; ");
            sb.append("Password: [PROTECTED]; ");
            sb.append("Enabled: ").append(this.enabled).append("; ");
            sb.append("AccountNonExpired: ").append(this.accountNonExpired).append("; ");
            sb.append("credentialsNonExpired: ").append(this.credentialsNonExpired)
                    .append("; ");
            sb.append("AccountNonLocked: ").append(this.accountNonLocked).append("; ");

            if (!authorities.isEmpty()) {
                sb.append("Granted Authorities: ");

                boolean first = true;
                for (GrantedAuthority auth : authorities) {
                    if (!first) {
                        sb.append(",");
                    }
                    first = false;

                    sb.append(auth);
                }
            }
            else {
                sb.append("Not granted any authorities");
            }

            return sb.toString();
        }

        public static MyUser.UserBuilder withUsername(String username) {
            return new MyUser.UserBuilder().username(username);
        }

        /**
         * Builds the user to be added. At minimum the username, password, and authorities
         * should provided. The remaining attributes have reasonable defaults.
         */
        public static class UserBuilder {
            private String username;
            private String password;
            private List<GrantedAuthority> authorities;
            private boolean accountExpired;
            private boolean accountLocked;
            private boolean credentialsExpired;
            private boolean disabled;

            /**
             * Creates a new instance
             */
            private UserBuilder() {
            }

            /**
             * Populates the username. This attribute is required.
             *
             * @param username the username. Cannot be null.
             * @return the {@link User.UserBuilder} for method chaining (i.e. to populate
             * additional attributes for this user)
             */
            private MyUser.UserBuilder username(String username) {
                Assert.notNull(username, "username cannot be null");
                this.username = username;
                return this;
            }

            /**
             * Populates the password. This attribute is required.
             *
             * @param password the password. Cannot be null.
             * @return the {@link User.UserBuilder} for method chaining (i.e. to populate
             * additional attributes for this user)
             */
            public MyUser.UserBuilder password(String password) {
                Assert.notNull(password, "password cannot be null");
                this.password = password;
                return this;
            }

            /**
             * Populates the roles. This method is a shortcut for calling
             * {@link #authorities(String...)}, but automatically prefixes each entry with
             * "ROLE_". This means the following:
             *
             * <code>
             *     builder.roles("USER","ADMIN");
             * </code>
             *
             * is equivalent to
             *
             * <code>
             *     builder.authorities("ROLE_USER","ROLE_ADMIN");
             * </code>
             *
             * <p>
             * This attribute is required, but can also be populated with
             * {@link #authorities(String...)}.
             * </p>
             *
             * @param roles the roles for this user (i.e. USER, ADMIN, etc). Cannot be null,
             * contain null values or start with "ROLE_"
             * @return the {@link User.UserBuilder} for method chaining (i.e. to populate
             * additional attributes for this user)
             */
            public MyUser.UserBuilder roles(String... roles) {
                List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>(
                        roles.length);
                for (String role : roles) {
                    Assert.isTrue(!role.startsWith("ROLE_"), role
                            + " cannot start with ROLE_ (it is automatically added)");
                    authorities.add(new SimpleGrantedAuthority("ROLE_" + role));
                }
                return authorities(authorities);
            }

            /**
             * Populates the authorities. This attribute is required.
             *
             * @param authorities the authorities for this user. Cannot be null, or contain
             * null values
             * @return the {@link User.UserBuilder} for method chaining (i.e. to populate
             * additional attributes for this user)
             * @see #roles(String...)
             */
            public MyUser.UserBuilder authorities(GrantedAuthority... authorities) {
                return authorities(Arrays.asList(authorities));
            }

            /**
             * Populates the authorities. This attribute is required.
             *
             * @param authorities the authorities for this user. Cannot be null, or contain
             * null values
             * @return the {@link User.UserBuilder} for method chaining (i.e. to populate
             * additional attributes for this user)
             * @see #roles(String...)
             */
            public MyUser.UserBuilder authorities(List<? extends GrantedAuthority> authorities) {
                this.authorities = new ArrayList<GrantedAuthority>(authorities);
                return this;
            }

            /**
             * Populates the authorities. This attribute is required.
             *
             * @param authorities the authorities for this user (i.e. ROLE_USER, ROLE_ADMIN,
             * etc). Cannot be null, or contain null values
             * @return the {@link User.UserBuilder} for method chaining (i.e. to populate
             * additional attributes for this user)
             * @see #roles(String...)
             */
            public MyUser.UserBuilder authorities(String... authorities) {
                return authorities(AuthorityUtils.createAuthorityList(authorities));
            }

            /**
             * Defines if the account is expired or not. Default is false.
             *
             * @param accountExpired true if the account is expired, false otherwise
             * @return the {@link User.UserBuilder} for method chaining (i.e. to populate
             * additional attributes for this user)
             */
            public MyUser.UserBuilder accountExpired(boolean accountExpired) {
                this.accountExpired = accountExpired;
                return this;
            }

            /**
             * Defines if the account is locked or not. Default is false.
             *
             * @param accountLocked true if the account is locked, false otherwise
             * @return the {@link User.UserBuilder} for method chaining (i.e. to populate
             * additional attributes for this user)
             */
            public MyUser.UserBuilder accountLocked(boolean accountLocked) {
                this.accountLocked = accountLocked;
                return this;
            }

            /**
             * Defines if the credentials are expired or not. Default is false.
             *
             * @param credentialsExpired true if the credentials are expired, false otherwise
             * @return the {@link User.UserBuilder} for method chaining (i.e. to populate
             * additional attributes for this user)
             */
            public MyUser.UserBuilder credentialsExpired(boolean credentialsExpired) {
                this.credentialsExpired = credentialsExpired;
                return this;
            }

            /**
             * Defines if the account is disabled or not. Default is false.
             *
             * @param disabled true if the account is disabled, false otherwise
             * @return the {@link User.UserBuilder} for method chaining (i.e. to populate
             * additional attributes for this user)
             */
            public MyUser.UserBuilder disabled(boolean disabled) {
                this.disabled = disabled;
                return this;
            }

            public UserDetails build() {
                return new User(username, password, !disabled, !accountExpired,
                        !credentialsExpired, !accountLocked, authorities);
            }
        }




    }



MyUserDetailService:

package urity.demo.support;

import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
import urity.demo.entity.User;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

//自定义用户处理的逻辑
//用户的信息的service
@Component
public class MyUserDetailService implements UserDetailsService {
    /**
     * 日志处理类
     */
    private org.slf4j.Logger logger =  LoggerFactory.getLogger(this.getClass());

    @Autowired
    private PasswordEncoder passwordEncoder;


    /**
     * 根据用户名加载用户信息
     *
     * @param username 用户名
     * @return UserDetails
     * @throws UsernameNotFoundException
     */

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        logger.info("表单登录用户名:" + username);
        System.out.println("表单登录用户名:" + username);
        List<GrantedAuthority> grantedAuthorityList = new ArrayList<>();
        grantedAuthorityList.add(new GrantedAuthority() {
            @Override
            public String getAuthority() {
                return "admin";
            }
        });

       User user = new User();
       user.setUsername("test");
       user.setPassword("123");

        String pWord =passwordEncoder.encode(user.getPassword());
        System.out.println("表单登录密码:" + pWord);

        MyUser myUser = new MyUser(username,pWord,AuthorityUtils.commaSeparatedStringToAuthorityList("admin,ROLE_USER"));


        return myUser;
    }
}

启动后和刚才一样进行认证即可.


以上是关于SpringSecurity自定义用户登录的主要内容,如果未能解决你的问题,请参考以下文章

[SpringSecurity]web权限方案_用户认证_自定义用户登录页面

Spring Security 3.x:如何使用自定义参数(不是用户名和密码)实现登录?

SpringSecurity 自定义表单登录

如何使用 Spring Security 自定义登录页面?

SpringSecurity基础功能详解

Spring boot 用户自定义访问控制,自定义登录页面,退出,用户信息获取