【问题标题】:Annotation based Spring Security for REST APIREST API 的基于注解的 Spring Security
【发布时间】:2016-07-08 12:18:40
【问题描述】:

我一直在尝试创建一个使用 Spring security 保护的 rest api

有关架构详情,请参阅此链接:Spring Security with REST architecture

但是,在我的实施过程中,我遇到了以下问题:

异常启动过滤器springSecurityFilterChain

我的应用程序实现是这样的:

@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

无状态认证安全配置

@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());
    }


}

无状态登录过滤器

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

它还直接将我重定向到服务,而不是向我显示输入用户名和密码的对话框。

【问题讨论】:

    标签: java spring rest spring-mvc spring-security


    【解决方案1】:

    如果你有这个文件,你能否尝试在 Spring.xml 或 ApplicationContext.xml 文件中配置组件扫描包。您也可以发布错误的堆栈跟踪。

    您可能还需要在 spring-security.xml 中配置 filterChainProxy 元素并将其绑定到 url 模式,如 /**

    【讨论】:

    • 我没有按照我的描述使用 xml,我提到我使用的是基于注释的配置
    • 我已经看到了同时使用 xml 和注释处理的示例,以防您想参考 mkyong.com/spring/… 。这通过在 XML 中包含基本的 xml 条目(如要扫描的包等)来工作,其余配置采用注释的形式。
    【解决方案2】:

    我有类似的设置。 不同的是,我有一个额外的 ContextLoaderListener 来加载 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;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-05-23
      • 2012-06-18
      • 2018-11-11
      • 2021-11-07
      • 2015-04-09
      • 2015-06-25
      • 2014-08-31
      • 2017-04-04
      相关资源
      最近更新 更多