![](/img/trans.png)
[英]Security for DataBase password and user login password in Spring and Java Encoder How to?
[英]How implement Spring security when login page having more field apart from user name and password?
我有一個登錄頁面,用戶需要在其中輸入以下信息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;
}
}
loginDetails對象如下所示
public class LoginDetails {
String vin;
String email;
String zipcode;
String accessCode;
}
在上述情況下如何使用彈簧安全。 在這里,用戶需要提供所有信息以驗證他自己。
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);
}
}
要從登錄表單中截取其他參數,您需要實現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);
}
}
要通過實現接口本身或擴展AbstractUserDetailsAuthenticationProvider
或DaoAuthenticationProvider
來驗證實現您自己的AuthenticationProvider
:
@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)
}
}
您只需要將您的實現傳遞給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>
希望這可以幫助!
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對象以從所需范圍獲取所需的屬性。
注意:這是一種靜態方法,這意味着它不會對單元測試友好。
如果要訪問底層的HttpServletRequest
還可以將RequestAttributes轉發給ServletRequestAttributes
希望這可以幫助。
這是您的答案,您需要實現自己的過濾器並覆蓋默認過濾器,以便將參數添加到登錄表單。
謝謝。 我創建了一個自定義過濾器類,用於根據三個參數(用戶名,密碼和帳戶ID)對用戶進行身份驗證。 我在SecurityConfig類中將它作為bean自動啟動:
@Bean
public AccountCredentialsAuthenticationFilter accountCredentialsAuthenticationFilter()
throws Exception {
AccountCredentialsAuthenticationFilter accountCredentialsAuthenticationFilter = new AccountCredentialsAuthenticationFilter();
accountCredentialsAuthenticationFilter
.setAuthenticationManager(authenticationManagerBean());
return accountCredentialsAuthenticationFilter;
}
因此,通過調用身份驗證所需的適當服務方法並為登錄用戶設置權限,我可以使用三個字段(用戶名,密碼和帳戶ID)執行身份驗證,而不僅僅是傳統的用戶名和密碼字段:
public class AccountCredentialsAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
@Autowired
private UserService userService;
@Qualifier("authenticationManager")
protected AuthenticationManager authenticationManager;
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
String account = request.getParameter("account");
final String userName = request.getParameter("userName");
final String password = request.getParameter("password");
boolean isFound = userService.checkLogin(userName, password, account);
if (isFound == true) {
boolean selectedAccount = false;
UserDetails userDetails = userService.loadUserByUsername(userName);
User user = (User) userDetails;
Set<Account> accounts = user.getAccounts();
String acctSelect = null;
// user has multiple accounts
for (Account acct : accounts) {
acctSelect = acct.getAccountId().toString();
if (acctSelect.equals(account)) {
// confirm which account user has logged in with
selectedAccount = true;
account = acctSelect;
request.getSession().setAttribute("account", account);
break;
}
}
if (selectedAccount) {
Set<? extends GrantedAuthority> authorities = (HashSet<? extends GrantedAuthority>) userDetails
.getAuthorities();
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(userName, password,
authorities);
token.setDetails(new WebAuthenticationDetails(request));
super.setDetails(request, token);
Authentication auth = this.getAuthenticationManager().authenticate(token);
SecurityContext securityContext = SecurityContextHolder.getContext();
securityContext.setAuthentication(auth);
// Create a new session and add the security context.
HttpSession session = request.getSession(true);
session.setAttribute("SPRING_SECURITY_CONTEXT", securityContext);
return auth;
} else {
SecurityContextHolder.getContext().setAuthentication(null);
request.getSession().setAttribute("SPRING_SECURITY_CONTEXT", null);
throw new UsernameNotFoundException("Please input correct credentials");
}
} else {
SecurityContextHolder.getContext().setAuthentication(null);
request.getSession().setAttribute("SPRING_SECURITY_CONTEXT", null);
throw new UsernameNotFoundException("Please input correct credentials");
}
}
在認證和授權之后,我覆蓋了UsernamePasswordAuthenticationFilter類的以下方法以進行適當的重定向:
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
Authentication authResult) throws IOException, ServletException {
RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
redirectStrategy.sendRedirect(request, response, "/home");
}
@Override
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
AuthenticationException failed) throws IOException, ServletException {
RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
redirectStrategy.sendRedirect(request, response, "/login?error=true");
}
我還修改了SecurityConfig類中的configure方法來執行自定義過濾器:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(accountCredentialsAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.authorizeRequests()....rest of the code....}
對於Spring Security中的自定義身份驗證,該方法
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response){---- call service methods here ----}
在此過濾器類(AccountCredentialsAuthenticationFilter)中,控制器類中的以下方法是多余的:
@RequestMapping(value = { "/login" }, method = RequestMethod.POST)
public String loginPage(@Valid @ModelAttribute("user") User user, BindingResult result, ModelMap model, HttpServletRequest request){---- call ervice methods here ----}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.