Spring安全记住我和自定义身份验证提供者



弹簧问题记住我

在我的spring安全应用程序中,我有自定义身份验证提供者进行身份验证并返回自定义身份验证对象,身份验证工作完美,但我有spring Remember me服务问题,它不能正常工作

但是当我通过正常的spring安全认证时,通过使用UserDetailService然后记住我的工作完美,我的代码都如下

package com.websopti.wotms.auth;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import com.websopti.wotms.entity.User;
import com.websopti.wotms.enums.ErrorKey;
import com.websopti.wotms.service.UserService;
@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
    @Autowired
    public UserService userService;
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String email = authentication.getPrincipal().toString();
        String password = authentication.getCredentials().toString();
        Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
        String username = null;
        try {
            username = userService.authenticate(email, password);
        } catch (IOException e) {
            e.printStackTrace();
        }
        if(username != null && !username.equals("0")){
            User user = userService.findByEmail(email);
            if (user != null) {
                authorities.add(new SimpleGrantedAuthority(user.getRole().name()));
                return (new UsernamePasswordAuthenticationToken(user, null, authorities));
            } else {
                User newUser = new User();
                newUser.setName(username);
                newUser.setEmail(email);
                newUser.setPassword(password);
                userService.register(newUser);
                newUser = userService.findById(newUser.getId());                
                authorities.add(new SimpleGrantedAuthority(newUser.getRole().name()));
                return (new UsernamePasswordAuthenticationToken(newUser, null, authorities));
            }
        } else {
            throw new UsernameNotFoundException(ErrorKey.USER_NOT_FOUND.name());
        }

    }
    @Override
    public boolean supports(Class<?> authentication) {
        return authentication.equals(UsernamePasswordAuthenticationToken.class);
    }
}

如果我使用以下代码进行身份验证,那么它可以正常工作

package com.websopti.wotms.auth;
import org.springframework.beans.factory.annotation.Autowired;
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.Service;
import com.websopti.wotms.entity.User;
import com.websopti.wotms.enums.ErrorKey;
import com.websopti.wotms.service.UserService;
@Service
public class AuthenticationService implements UserDetailsService {
    @Autowired
    public UserService userService;
    @Override
    public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
        User user = userService.findByEmail(email);
        if(user != null)
            return user;
        else
            throw new UsernameNotFoundException(ErrorKey.USER_NOT_FOUND.name());
    }
}

谁能告诉我我的代码中有什么问题?

根据doc

注意这两个实现都需要一个UserDetailsService。如果你使用的身份验证提供程序不使用UserDetailsService(例如,LDAP提供程序),那么它将无法工作除非您的应用程序中也有UserDetailsService bean上下文。

示例默认remember-me使用TokenBasedRememberMeServices processAutoLoginCookie()方法从cookie中检索userDetails来验证用户/密码详细信息。所以你需要一个自定义userDetailsService检查这个或这个

更新:

基本上记住我的功能做两件事

  1. 成功登录后,它创建一个"记住我"浏览器cookie与一个令牌基于用户名,密码(令牌可以计算和持久化在数据库中,如果需要,或者它可以在飞行计算哈希的用户,密码)。
  2. 当用户试图在没有任何会话的情况下访问安全页面时(会话因超时而过期),那么memorberme服务将尝试通过从cookie中检索用户详细信息来自动登录用户,并且可以在需要时验证用户详细信息。

如果你没有UserDetailsService返回UserDetails信息,那么你需要实现像TokenBasedRememberMeServices这样的RememberMeServices并调整代码。

我有同样的问题,并添加auth.userDetailsService(userService);修复它

  @Autowired
  private AuthenticationService userDetailsService;
  @Autowired
  private CustomAuthenticationProvider provider;
  @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        //将验证过程交给自定义验证工具
        auth.userDetailsService(userService);
        auth.authenticationProvider(provider);
    }

当你使用Spring自定义身份验证提供程序时,你需要创建自己的remember me服务并将其配置到Spring安全配置文件中。

链接如下:https://samerabdelkafi.wordpress.com/2016/01/25/secure-angularjs-application-with-spring-security/

记住我和自定义身份验证提供程序的问题是:

  1. 您已经在自定义身份验证提供者中进行了身份验证。
  2. 之后,记得我过滤器在春季安全链再次调用userdetails服务。此时,userdetail服务将认证主体作为输入参数,您无法从dbo获取任何用户详细信息,并且它不会执行此过滤器。

public UserDetails loadUserByUsername(String mobile)抛出UsernameNotFoundException {System.out.println(移动);//在这里可以如果您已经进行了身份验证,则获取已验证的主体用户对象将不会获得任何用户详细信息。}

我不确定下面的解决方案是否正确,但它对我来说很好。

public Authentication authenticate(Authentication auth) throws AuthenticationException {
    Customer user = null;
    user = customerDataManager.findCustomerByMobile(auth.getName());
    if ((user == null)) {
        throw new BadCredentialsException("Invalid username or password");
    }
    final Authentication result = super.authenticate(auth);
    return result;
}

代替返回UsernamePasswordAuthenticationToken对象返回认证对象

最新更新