当用户名和密码除了具有更多字段的登录页面时如何实现Spring安全性?

Kru*_*hna 8 java spring spring-mvc spring-security

我有一个登录页面,用户需要在其中输入以下信息VIN号码,电子邮件,邮政编码和accessCode,他们将从不同的应用程序中获取.

因此,要验证用户,我需要自定义UserDetailsService类中的所有信息,然后将调用一个过程来验证用户.

但是当我实现UserDetailsService下面这样的时候,我看到了

@Component
 public class LoginService implements UserDetailsService {
@Autowired
LoginStoredProcedureDao loginStoredProcedureDao;

public Map<String, Object> verifyLogin(LoginDetails details) {
    return loginStoredProcedureDao.verifyLogin(details);

}
@Override
public UserDetails loadUserByUsername(String username)
        throws UsernameNotFoundException {
    // TODO Auto-generated method stub
      //verifyLogin();
    return null;
}

}
Run Code Online (Sandbox Code Playgroud)

loginDetails对象如下所示

public class LoginDetails {
String vin;
String email;
String zipcode;
String accessCode;
}
Run Code Online (Sandbox Code Playgroud)

在上述情况下如何使用弹簧安全.在这里,用户需要提供所有信息以验证他自己.

Roa*_*ner 9

UserDetailsService验证Authentication令牌不是响应性.这就是它的AuthenticationProvider作用.

因此,首先要执行UserDetailsService从数据库加载用户的所有数据的单一职责login:

@Component
public class UserDetailsServiceImpl implements UserDetailsService {

    private final UserRepository userRepository;

    @Autowired
    public UserDetailsServiceImpl(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = null;
        try {
            user = userRepository.findByUsername(username);
        } catch (NotFoundException e) {
            throw new UsernameNotFoundException(String.format("No user found for username %s!", username);
        }
        retrun new UserDetailsImpl(user);
    }
}
Run Code Online (Sandbox Code Playgroud)

比从您需要实现的登录表单中截取其他参数AuthenticationDetailsSource.扩展可能是一个好主意WebAuthenticationDetails,但您可以只返回任何返回的对象AuthenticationDetailsSource.

@Component
public class WebAuthenticationDetailsSourceImpl implements AuthenticationDetailsSource<HttpServletRequest, MyWebAuthenticationDetails> {

    @Override
    public MyWebAuthenticationDetails buildDetails(HttpServletRequest context) {
        // the constructor of MyWebAuthenticationDetails can retrieve
        // all extra parameters given on a login form from the request
        // MyWebAuthenticationDetails is your LoginDetails class
        return new MyWebAuthenticationDetails(context);
    }
}
Run Code Online (Sandbox Code Playgroud)

AuthenticationProvider通过实现接口本身或扩展AbstractUserDetailsAuthenticationProvider或执行验证实现自己的DaoAuthenticationProvider:

@Component
public class UserDetailsAuthenticationProviderImpl extends AbstractUserDetailsAuthenticationProvider {

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        MyWebAuthenticationDetails detais = (MyWebAuthenticationDetails) authentication.getDetails();
        // verify the authentication details here !!!
        // and return proper authentication token (see DaoAuthenticationProvider for example)
    }
}
Run Code Online (Sandbox Code Playgroud)

比你只需要将你的实现传递给AuthenticationManagerUsernamePasswordAuthenticationFilter.

<util:list id="authenticationProviders">
    <ref bean="userDetailsAuthenticationProviderImpl" />
</util:list>

<!-- 
    This bean MUST have this exact ID to be the default authenticationManager!
    This is required prior Spring 3.1, as authentication-manager-ref is not
    present in sec:http element before!
 -->
<bean id="org.springframework.security.authenticationManager"
    name="authenticationManager"
    class="org.springframework.security.authentication.ProviderManager"
    c:providers-ref="authenticationProviders" />

<bean id="usernamePasswordAuthenticationFilter"
    class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter"
    p:authenticationManager-ref="authenticationManager"
    p:authenticationDetailsSource-ref="webAuthenticationDetailsSourceImpl" />

<sec:http authentication-manager-ref="authenticationManager">
    <sec:custom-filter position="FORM_LOGIN_FILTER" ref="usernamePasswordAuthenticationFilter" />
</sec:http>
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助!

PS考虑构造函数注入场注入!它更可测试并更好地说明了课程的合同.见这个讨论.


Aks*_*hay 7

首先,我会以不同的方式解决您的问题.我会做一个多步验证.第一个是传统的用户名/密码登录,使用spring security的默认模型.第二步是显示另一个表单,该表单必须由用户填写,以提供应用程序想要强制执行的身份验证的其他详细信息.

无论如何,如果您想继续自定义弹簧安全模型,只需一步即可了解有关登录的更多详细信息.按照@Petr上一个答案中的步骤参考.然后要访问UserDetailsS​​ervice类中的会话属性,请使用Spring提供的http://static.springsource.org/spring/docs/2.0.8/api/org/springframework/web/context/request/RequestContextHolder.html类.

您可以访问currentRequestAttributes(),返回一个RequestAttributes对象.您可以查询RequestAttributes对象以从所需范围获取所需的属性.

注意:这是一种静态方法,这意味着它不会对单元测试友好.

ServletRequestAttributes如果您想要访问底层证书,也可以将RequestAttributes转发给HttpServletRequest

希望这可以帮助.