Tôi đang sử dụng Spring Security để bảo mật ứng dụng web Struts2. Do các ràng buộc của dự án, tôi đang sử dụng Spring Security 2.06.Triển khai AuthenticationProvider tùy chỉnh trong Spring Security 2.06
đội Mỹ xây dựng một API quản lý tùy chỉnh người dùng mà xác thực người dùng sau khi uống vào tên người dùng và mật khẩu thông số, và trả về một đối tượng người dùng tùy chỉnh chứa danh sách các vai trò và các thuộc tính khác như email, tên, vv
Từ sự hiểu biết của tôi, trường hợp sử dụng bảo mật Spring điển hình sử dụng một UserDetailsService mặc định để lấy ra một đối tượng UserDetails; đối tượng này sẽ chứa (trong số những thứ khác) một trường mật khẩu sẽ được khung công tác sử dụng để xác thực người dùng.
Trong trường hợp của mình, tôi muốn cho API tùy chỉnh của chúng tôi thực hiện xác thực, sau đó trả về đối tượng UserDetails tùy chỉnh chứa các vai trò và các thuộc tính khác (email, v.v ...).
Sau một số nghiên cứu, tôi đã tìm ra rằng tôi có thể thực hiện việc này thông qua triển khai tùy chỉnh AuthenticationProvider. Tôi cũng có triển khai tùy chỉnh UserDetailsService và UserDetails.
Vấn đề của tôi là tôi không thực sự hiểu những gì tôi phải quay trở lại trong CustomAuthenticationProvider. Tôi có sử dụng đối tượng UserDetailsService tùy chỉnh của mình ở đây không? Đó có cần thiết không? Xin lỗi, tôi thực sự bối rối.
CustomAuthenticationProvider:
public class CustomAuthenticationProvider implements AuthenticationProvider {
private Logger logger = Logger.getLogger(CustomAuthenticationProvider.class);
private UserDetailsService userDetailsService; //what am i supposed to do with this?
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
UsernamePasswordAuthenticationToken auth = (UsernamePasswordAuthenticationToken) authentication;
String username = String.valueOf(auth.getPrincipal());
String password = String.valueOf(auth.getCredentials());
logger.info("username:" + username);
logger.info("password:" + password);
/* what should happen here? */
return null; //what do i return?
}
@Override
public boolean supports(Class aClass) {
return true; //To indicate that this authenticationprovider can handle the auth request. since there's currently only one way of logging in, always return true
}
public UserDetailsService getUserDetailsService() {
return userDetailsService;
}
public void setUserDetailsService(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
}
applicationContext-security.xml:
<beans:bean id="customUserDetailsService" scope="prototype" class="com.test.testconsole.security.CustomUserDetailsService"/>
<beans:bean id="customAuthenticationProvider" class="com.test.testconsole.security.CustomAuthenticationProvider">
<custom-authentication-provider />
<beans:property name="userDetailsService" ref="customUserDetailsService" />
</beans:bean>
Nói tóm lại, đây là những gì tôi cần:
- người dùng đăng nhập thông qua biểu mẫu web
- Authenticate người dùng sử dụng trong nhà quản lý người dùng API
- Đối với người dùng xác thực thành công, cư GrantedAuthories vv
Return một thực thể người dùng chứa vai trò/cơ quan chức năng và các thuộc tính khác như email, tên, vv Tôi nên sau đó có thể truy cập đối tượng này như vậy ..
//spring security get user name Authentication auth = SecurityContextHolder.getContext().getAuthentication(); userName = auth.getName(); //get logged in username logger.info("username: " + userName); //spring security get user role GrantedAuthority[] authorities = auth.getAuthorities(); userRole = authorities[0].getAuthority(); logger.info("user role: " + userRole);
tôi hy vọng điều này có ý nghĩa. Bất kỳ trợ giúp hoặc con trỏ sẽ được đánh giá cao!
Cảm ơn!
Cập nhật:
Tôi đã thực hiện một số tiến bộ, tôi nghĩ vậy.
Tôi có một đối tượng tùy chỉnh Xác thực thi giao diện Xác thực:
public class CustomAuthentication implements Authentication {
String name;
GrantedAuthority[] authorities;
Object credentials;
Object details;
Object principal;
boolean authenticated;
public CustomAuthentication(String name, GrantedAuthority[] authorities, Object credentials, Object details, Object principal, boolean
authenticated){
this.name=name;
this.authorities=authorities;
this.details=details;
this.principal=principal;
this.authenticated=authenticated;
}
@Override
public GrantedAuthority[] getAuthorities() {
return new GrantedAuthority[0]; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public Object getCredentials() {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public Object getDetails() {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public Object getPrincipal() {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public boolean isAuthenticated() {
return false; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public String getName() {
return null;
}
}
và cập nhật lớp CustomerAuthenticationProvider tôi:
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
UsernamePasswordAuthenticationToken auth = (UsernamePasswordAuthenticationToken) authentication;
String username = String.valueOf(auth.getPrincipal());
String password = String.valueOf(auth.getCredentials());
logger.info("username:" + username);
logger.info("password:" + password);
//no actual validation done at this time
GrantedAuthority[] authorities = new GrantedAuthorityImpl[1];
authorities[0] = new GrantedAuthorityImpl("ROLE_USER");
CustomAuthentication customAuthentication = new CustomAuthentication("TestMerchant",authorities,"details",username,password,true);
return customAuthentication;
//return new UsernamePasswordAuthenticationToken(username,password,authorities);
}
Nó hoạt động nếu tôi trả về một đối tượng UsernamePasswordAuthenticationToken, nhưng nếu tôi cố gắng quay trở lại CustomAuthentication, tôi nhận được lỗi sau:
java.lang.ClassCastException: com.test.testconsole.security.CustomAuthentication cannot be cast to org.springframework.security.providers.UsernamePasswordAuthenticationToken
at com.test.testconsole.security.CustomAuthenticationProvider.authenticate(CustomAuthenticationProvider.java:27)
at org.springframework.security.providers.ProviderManager.doAuthentication(ProviderManager.java:188)
at org.springframework.security.AbstractAuthenticationManager.authenticate(AbstractAuthenticationManager.java:46)
at org.springframework.security.intercept.AbstractSecurityInterceptor.authenticateIfRequired(AbstractSecurityInterceptor.java:319)
at org.springframework.security.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:258)
at org.springframework.security.intercept.web.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:106)
at org.springframework.security.intercept.web.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
at org.springframework.security.ui.SessionFixationProtectionFilter.doFilterHttp(SessionFixationProtectionFilter.java:67)
at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
at org.springframework.security.ui.ExceptionTranslationFilter.doFilterHttp(ExceptionTranslationFilter.java:101)
at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
at org.springframework.security.providers.anonymous.AnonymousProcessingFilter.doFilterHttp(AnonymousProcessingFilter.java:105)
at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
at org.springframework.security.ui.rememberme.RememberMeProcessingFilter.doFilterHttp(RememberMeProcessingFilter.java:116)
at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
at org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter.doFilterHttp(SecurityContextHolderAwareRequestFilter.java:91)
at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
at org.springframework.security.ui.basicauth.BasicProcessingFilter.doFilterHttp(BasicProcessingFilter.java:174)
at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
at org.springframework.security.ui.AbstractProcessingFilter.doFilterHttp(AbstractProcessingFilter.java:278)
at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
at org.springframework.security.ui.logout.LogoutFilter.doFilterHttp(LogoutFilter.java:89)
at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
at org.springframework.security.context.HttpSessionContextIntegrationFilter.doFilterHttp(HttpSessionContextIntegrationFilter.java:235)
at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
at org.springframework.security.util.FilterChainProxy.doFilter(FilterChainProxy.java:175)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:236)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
at org.mortbay.jetty.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:230)
at org.mortbay.jetty.handler.HandlerCollection.handle(HandlerCollection.java:114)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
at org.mortbay.jetty.Server.handle(Server.java:326)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:536)
at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:915)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:539)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:212)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:405)
at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:409)
at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
Nó giống như một cái gì đó được mong đợi không chỉ bất kỳ đối tượng xác thực, nhưng thực hiện cụ thể của nó - UsernamePasswordAuthenticationToken. Điều này làm cho tôi nghĩ rằng tôi có thể thiếu một thành phần tùy chỉnh khác .. có thể là một bộ lọc?
Hi Luke, nhờ trả lời của bạn! Tôi thực sự đã thực hiện một chút tiến bộ sau khi đăng câu hỏi và những gì tôi đã làm trông giống như những gì bạn đề nghị. Tôi vẫn có vấn đề không thể thêm các trường bổ sung như (email, v.v.) vào đối tượng Authentication. Tôi đã triển khai lớp xác thực tùy chỉnh nhưng gặp lỗi. Vui lòng xem nội dung cập nhật của tôi .. – shaunlim
Có vẻ như bạn đang thực hiện một dàn diễn viên không hợp lệ trong CustomAuthenticationProvider, dòng 27 của bạn vào UsernamePasswordAuthenticationToken. Thường không cần phải tạo một đối tượng xác thực tùy chỉnh. –
oh .. tôi hiểu rồi. Bạn có nghĩa là thay vì đi qua trong tên người dùng như là chính cho constructor UsernamePasswordAuthenticationToken, tôi nên vượt qua trong đối tượng người dùng tùy chỉnh của tôi có chứa tất cả các trường thêm tôi cần? sau đó khi tôi cần dữ liệu, tôi sẽ chỉ gọi getPrincipal sau khi truy xuất đối tượng Authentication? – shaunlim