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)
在上述情况下如何使用弹簧安全.在这里,用户需要提供所有信息以验证他自己.
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)
比你只需要将你的实现传递给AuthenticationManager和UsernamePasswordAuthenticationFilter.
<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考虑构造函数注入场注入!它更可测试并更好地说明了课程的合同.见这个讨论.
首先,我会以不同的方式解决您的问题.我会做一个多步验证.第一个是传统的用户名/密码登录,使用spring security的默认模型.第二步是显示另一个表单,该表单必须由用户填写,以提供应用程序想要强制执行的身份验证的其他详细信息.
无论如何,如果您想继续自定义弹簧安全模型,只需一步即可了解有关登录的更多详细信息.按照@Petr上一个答案中的步骤参考.然后要访问UserDetailsService类中的会话属性,请使用Spring提供的http://static.springsource.org/spring/docs/2.0.8/api/org/springframework/web/context/request/RequestContextHolder.html类.
您可以访问currentRequestAttributes(),返回一个RequestAttributes对象.您可以查询RequestAttributes对象以从所需范围获取所需的属性.
注意:这是一种静态方法,这意味着它不会对单元测试友好.
ServletRequestAttributes如果您想要访问底层证书,也可以将RequestAttributes转发给HttpServletRequest
希望这可以帮助.