【问题标题】:Using Custom class instead of User class in spring security for encoding and password authentication在spring security中使用自定义类而不是用户类进行编码和密码认证
【发布时间】:2016-08-04 01:11:06
【问题描述】:

我是 Spring Security 的新手。我有 Android application and JAVA as back end 服务。客户服务已通过 REST 公开。

我的要求是在注册过程中对客户的密码进行编码并将其保存到数据库中,然后我可以在 java 后端使用 Spring Security 对其进行身份验证。在注册和登录过程中,所有客户数据都以 JSON 格式从 Android 提供

我看到 Spring 有自己的 User 和 UserService 类用于身份验证。

我需要使用 Customer 类而不是 USER(Spring 提供的 bean) 类。Customer Bean 将密码作为字段。有没有办法在spring security中使用我们自己的类和表?如何在登录时解码密码并稍后进行身份验证?请说明一下,因为我严格要求不要使用 Spring 的 User 类

客户 Bean

@XmlRootElement(name = "customer")
@XmlAccessorType(value = XmlAccessType.FIELD)
public class CustomerWrapper {

    @XmlElement
    protected Long id;

    @XmlElement
    protected String firstName;

    @XmlElement
    protected String lastName;

    @XmlElement
    protected String emailAddress;
    @XmlElement
    protected String username;

    @XmlElement
    protected String primaryPhone;

    @XmlElement
    protected String secondaryPhone;

    @XmlElement
    protected String password;

    @XmlElement(name = "customerAddress")
    @XmlElementWrapper(name = "customerAddress")
    protected List<AddressWrapper> customerAddress = new ArrayList<AddressWrapper>();

setter and getter

【问题讨论】:

  • 您到底对什么感兴趣?如何保存密码,如何登录?我有一个使用我自己的 User 类的 Spring 应用程序。
  • @RaphaelRoth 实际上我想先对密码进行编码,然后再使用 Spring Security 进行身份验证以进行登录过程

标签: java spring spring-security


【解决方案1】:

您可以选择从 spring 框架扩展 UserDetailsS​​ervice 并创建一个自定义 CustomerUserDetails 来从客户创建一个用户

@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {
    @Autowired
    private CustomerService customerService // here it's your CustomerService 
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
    UserDetails userDetails = null;
    Customer customer = custermerService.login(username);
    userDetails = new CustomerUserDetails(customer);
    return userDetails;
}

CustomerUserDetails类应该继承User,或者从spring实现UserDetails并创建一个对应的User。基本上它需要一个用户名、密码和 GrantedAuthorities

public class CustomerUserDetails implements org.springframework.security.core.userdetails.UserDetails{
//must provide here username, password and GrantedAutority
}

【讨论】:

  • 感谢您的解决方案,但是否有可能在不扩展 Spring 的 UserDetails 或 User 类的情况下,我可以在登录时直接使用我的客户类进行密码编码和身份验证
  • 不,你不能只使用你的 Customer 类,因为在内部,spring security 与 User、UserDetails 和 UserDetailsS​​ervice 一起工作(这就是为什么 CustomerUserDetails 应该实现 UserDetails,你可以从客户那里构造一个用户) .你必须坚持他们。将它们视为您的应用程序和 Spring 安全框架之间的合同。
【解决方案2】:

是的,可以使用您自己的用户类(在我的示例中为MyUser)。你需要什么:

您的自定义MyUserService 必须实现UserDetailsService,这会强制您实现loadUserByUsername:

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

    MyUser user = myUserRepository.findByUsername(username);
    if (user == null) {
        String msg = String.format("UserAccount '%s' not found.", username);
        throw new UsernameNotFoundException(msg);
    }
    // assign authorities to the user:
     Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
    authorities.add(new SimpleGrantedAuthority("ROLE_REGISTERED"));

    User springUser = new User(user.getUsername(), user.getPassword(), authorities);
    return springUser;
}

在上面的代码中,您返回了一个 Spring 特定的用户,但您不需要使用它,它只是用于身份验证管理器。

在您的 xml 配置中,您需要将您的 MyUserService 与 Spring 的 AuthenticationManager 连接起来:

<bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" c:strength="12" />
<!-- manager responsible for loading user account with assigned roles -->
<sec:authentication-manager alias="authenticationManager">
    <sec:authentication-provider user-service-ref="myUserService">
        <sec:password-encoder ref="passwordEncoder" />
    </sec:authentication-provider>
</sec:authentication-manager>

要登录(即对用户进行身份验证),您需要执行以下操作(我把它放在我的AuthenticationService:

public boolean login(String username, String password) {
    try {
        Authentication authenticate = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
        if (authenticate.isAuthenticated()) {
            SecurityContextHolder.getContext().setAuthentication(authenticate);
            return true;
        }
    } catch (BadCredentialsException e) {
        logger.warn("User {} tried to log in with bad credentials", username);
    } catch (RuntimeException e) {
        logger.error("An error occured during login of user {}", username, t);
    }
    return false;
}

获取您当前登录的MyUser:

public MyUser getLoggedInMyUser()  {
    try {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        if (auth != null) {
            return myUserService.findByUsername(auth.getName());
        }
        return null;
    } catch (RuntimeException e) {
        logger.error("An error occurred while getting logged in User.", e);
        logout();
    }
}

【讨论】:

    猜你喜欢
    • 2011-12-01
    • 2020-01-18
    • 2012-03-07
    • 2017-12-25
    • 2012-02-08
    • 2016-05-16
    • 2018-06-27
    • 2016-02-29
    • 2013-11-03
    相关资源
    最近更新 更多