问题
I have been trying to create a rest api secured with Spring security
For the architecture details kindly see this link: Spring Security with REST architecture
But, during my implementation I am facing following issues like :
Exception starting filter springSecurityFilterChain
My application implementation is like :
@EnableWebMvc
@Configuration
@ComponentScan({ "com.ws.service.*" })
public class AppConfig extends Application {
...
}
CustomJDBCDaoImpl
public class CustomJDBCDaoImpl extends JdbcDaoImpl {
public CustomJDBCDaoImpl() {
// TODO Auto-generated constructor stub
super();
}
private DataSource getDataSourceFromJndi() {
...
}
@Override
protected List<GrantedAuthority> loadGroupAuthorities(String username) {
...
}
@Override
public UserDetails loadUserByUsername(String username) {
...
}
private UpUser findUserByScreenName(String userName) {
...
}
private ResultSet executeQuery(String sql){
...
}
}
Source code for Stateless Authentication Filter
Stateless Authentication Security Config
@EnableWebSecurity
@Configuration
@Order(1)
public class StatelessAuthenticationSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private TokenAuthenticationService tokenAuthenticationService;
public StatelessAuthenticationSecurityConfig() {
super(true);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.exceptionHandling().and()
.anonymous().and()
.servletApi().and()
.headers().cacheControl().and()
.authorizeRequests()
//allow anonymous resource requests
.antMatchers("/").permitAll()
.antMatchers("/favicon.ico").permitAll()
.antMatchers("/resources/**").permitAll()
//allow anonymous POSTs to login
.antMatchers(HttpMethod.POST, "/api/login").permitAll()
//allow anonymous GETs to API
.antMatchers(HttpMethod.GET, "/api/**").permitAll()
//defined Admin only API area
.antMatchers("/admin/**").hasRole("ADMIN")
//all other request need to be authenticated
.anyRequest().hasRole("USER").and()
// custom JSON based authentication by POST of {"username":"<name>","password":"<password>"} which sets the token header upon authentication
.addFilterBefore(new StatelessLoginFilter("/api/login", tokenAuthenticationService, new CustomJDBCDaoImpl(), authenticationManager()), UsernamePasswordAuthenticationFilter.class)
// custom Token based authentication based on the header previously given to the client
.addFilterBefore(new StatelessAuthenticationFilter(tokenAuthenticationService), UsernamePasswordAuthenticationFilter.class);
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(new CustomJDBCDaoImpl()).passwordEncoder(new BCryptPasswordEncoder());
}
}
Stateless Login Filter
class StatelessLoginFilter extends AbstractAuthenticationProcessingFilter {
private final TokenAuthenticationService tokenAuthenticationService;
private final CustomJDBCDaoImpl userDetailsService;
protected StatelessLoginFilter(String urlMapping, TokenAuthenticationService tokenAuthenticationService,
CustomJDBCDaoImpl userDetailsService, AuthenticationManager authManager) {
super(new AntPathRequestMatcher(urlMapping));
this.userDetailsService = userDetailsService;
this.tokenAuthenticationService = tokenAuthenticationService;
setAuthenticationManager(authManager);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException, IOException, ServletException {
final UsernamePasswordAuthenticationToken loginToken = new UsernamePasswordAuthenticationToken(
request.getParameter("username").toString(), request.getParameter("password").toString());
return getAuthenticationManager().authenticate(loginToken);
}
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
FilterChain chain, Authentication authentication) throws IOException, ServletException {
// Lookup the complete User object from the database and create an Authentication for it
final UserDetails authenticatedUser = userDetailsService.loadUserByUsername(authentication.getName());
final UserAuthentication userAuthentication = new UserAuthentication(authenticatedUser);
// Add the custom token as HTTP header to the response
tokenAuthenticationService.addAuthentication(response, userAuthentication);
// Add the authentication to the Security context
SecurityContextHolder.getContext().setAuthentication(userAuthentication);
}
}
Source Code for Token Authentication Service
Source Code for Token Handler
Also it's directly redirecting me to the service instead of showing me a dialog to enter username and password.
回答1:
i have a similar setup. the difference is, i have an additional ContextLoaderListener to load the SpringSecurityFilerChain
@WebListener
public class SpringContextLoader extends ContextLoaderListener {
@Override
protected WebApplicationContext createWebApplicationContext(final ServletContext sc) {
AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
applicationContext.register(SpringConfiguration.class);
sc.addFilter("springSecurityFilterChain", new DelegatingFilterProxy("springSecurityFilterChain")).addMappingForUrlPatterns(null, false, "/*");
Dynamic dynamic = sc.addServlet("dispatcher", new DispatcherServlet(applicationContext));
dynamic.addMapping("/");
dynamic.setLoadOnStartup(1);
return applicationContext;
}
}
回答2:
Can you try to configure the component scan package in Spring.xml or ApplicationContext.xml file as well in case you have this file. Also can you post the stack trace of the error.
You may also need to configure the filterChainProxy element in spring-security.xml and bind it to url pattern like /**
来源:https://stackoverflow.com/questions/36140375/annotation-based-spring-security-for-rest-api