Annotation based Spring Security for REST API

倾然丶 夕夏残阳落幕 提交于 2019-12-25 04:37:16

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!