如何在自定义java类/自定义Spring框架中使用Spring安全性';什么课?

如何在自定义java类/自定义Spring框架中使用Spring安全性';什么课?,java,spring,security,spring-security,Java,Spring,Security,Spring Security,我的要求如下: 在我们的应用程序中,用户的凭证第一次根据数据库进行验证(因为它是一个遗留应用程序,所以不使用spring security)。如果用户是有效用户,他将登录到应用程序。一旦用户登录到应用程序中,他就可以进行一些rest调用。现在,在进行任何rest调用之前,我想再次使用spring security验证用户的凭据。这里的挑战是我们不应该重新设计数据库模式。我们需要使用一个存储过程来验证用户。如果身份验证失败,此特定存储过程将返回错误消息,否则将不返回任何内容。本例中未定义任何角色。

我的要求如下:

在我们的应用程序中,用户的凭证第一次根据数据库进行验证(因为它是一个遗留应用程序,所以不使用spring security)。如果用户是有效用户,他将登录到应用程序。一旦用户登录到应用程序中,他就可以进行一些rest调用。现在,在进行任何rest调用之前,我想再次使用spring security验证用户的凭据。这里的挑战是我们不应该重新设计数据库模式。我们需要使用一个存储过程来验证用户。如果身份验证失败,此特定存储过程将返回错误消息,否则将不返回任何内容。本例中未定义任何角色。只需使用存储过程进行简单的身份验证。现在,我想通过spring security完成这一切。可能正在编写java类/自定义spring框架的类,在其中调用存储过程,并在spring安全配置文件中使用该类。有谁能提出一些关于如何创业的建议吗

我已经实现了AuthenticationProvider。以下是*security.xml文件

  <http auto-config="true"  use-expressions="true">
    <intercept-url pattern="/rest/*" access="permitAll"></intercept-url>
</http>

    <authentication-manager >
    <authentication-provider ref="csAuthenticationProvider" />
</authentication-manager>


但是,安全框架正在寻找角色。在我的例子中,没有定义角色。如前所述,用户第一次在不使用spring框架的情况下进行身份验证。如果用户想要进行任何rest调用,spring安全性需要重新验证用户。这并不意味着用户需要重新输入凭据。用户的凭据在rest调用/请求中可用,因为他已通过身份验证。唯一需要做的是,我需要使用请求来使用凭据,并使用存储过程重新验证。当然,使用AuthenticationProvider可能是一个好主意,但是authenticate(Authentication)方法的参数“Authentication”对我来说没有用处,因为我需要再次调用自己的存储过程调用。目前,我没有使用Authentication对象,而是使用authenticate()方法中调用代码的存储过程。但奇怪的是,没有调用authenticate()方法。我感到惊讶和困惑。有人知道我哪里做错了吗?

听起来你需要实现一个身份验证提供者。下面是一个非常简单的示例,我认为您可以适应调用存储过程


您可以实现自己的UserDetails服务,并将spring配置为使用它

<security:authentication-manager>
    <security:authentication-provider user-service-ref="userDetailsServiceImpl"/>
</security:authentication-manager>

您需要创建一个自定义的UserDetailsService实现,它将根据DB进行检查

下面是一个示例UserDetailsService实现,它可以实现以下功能:

@Service("userService")
public class UserDetailsServiceImpl implements UserDetailsService, InitializingBean {

    @Autowired
    private AccountService accountService;

    public void afterPropertiesSet() throws Exception {
    }

    @Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
        username = username.toLowerCase();
        try {
            Account account = accountService.loadUserAccountByEmail(username);
            if (account == null) {
                throw new UsernameNotFoundException("Could not find email: " + username + "in the DB.");
            }

            List<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();
            for (Role r : account.getRoles()) {
                auths.add(new SimpleGrantedAuthority(r.getRole()));
            }
            ApplicationUser user = null;
            try {
                user = new ApplicationUser(new Long(account.getId()), username, account.getPassword(), true, true, true, true, auths);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            return user;
        } catch (Exception e) {
            e.printStackTrace();
            throw new UsernameNotFoundException(username + "not found", e);
        }
    }

}

(你也可以看到我写的一篇关于从xml切换到@annotation config for spring security的博客文章,这里引用了该项目:)

谢谢你的快速回复。我会看看你发布的链接。你能看看编辑的内容并提出一些建议吗?谢谢你的快速回复。起初,我也这么认为。如果我们实现UserDetailsService,我们需要重写loadUserByUsername(字符串用户名)。但是,无论如何,UserDetailsService类没有被调用。如果你想看一看,我会发布代码。请看我在rhinds问题中的评论-UserDetails服务不进行身份验证(请参阅。如果您想封装自己的身份验证代码,最好直接实现AuthenticationProvider。感谢Luke的回答。我将尝试按照您所说的实现AuthenticationProvider,并在发现任何问题时通知您。要求是使用存储过程来执行身份验证。UserDetails服务doesn不执行身份验证,所以这不是一个合适的选项。啊,是的。你是对的-我把它理解为只是获取用户数据的存储过程-掩盖了关于在DB中进行实际身份验证的部分。Luke,你能看看编辑的内容并提出一些建议吗?如果有人能分享我的问题的伪代码,那就太好了。请更具体地描述你正在做什么。你说“安全框架正在寻找角色”。这意味着什么?实际调用的代码是什么?还要解释,如果没有可用凭据,并且您不希望用户提供任何凭据,您希望Spring Security如何对用户进行身份验证。如果您希望只使用与他们登录时相同的HTTP会话,那么在对用户进行身份验证时,您需要创建一个安全会话ty上下文,Spring Security可用于未来的请求。Luke,谢谢!,“安全框架正在寻找角色”:这意味着根据我的要求,不需要验证角色。当用户第一次登录时,用户输入的凭据存储在请求对象中。我需要使用这些凭据并使用spring security(通过存储过程调用)重新验证。当用户登录时,我可以使用相同的HTTP会话。请您指导我如何获得相同的HTTP会话,创建Spring安全上下文,并按照上述要求重新验证。如果您可以共享一些伪代码,那就太好了。
@Override
     protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
         auth
            .userDetailsService(userDetailsServiceImpl)
            .passwordEncoder(bCryptPasswordEncoder());
     }