代码之家  ›  专栏  ›  技术社区  ›  rob

如何从angularjs控制器向REST控制器提交包括CSRF令牌在内的数据?

  •  -1
  • rob  · 技术社区  · 6 年前

    我正在尝试使用从角度控制器到静止控制器从模态提交数据。这个 放,拿,发 方法工作代码仅在CSRF为 解散 但当我 使可能 PUT和POST的CSRF不工作。我查了一下控制台日志,上面写着 405(方法不允许) .

    我知道我需要把数据和 csrf令牌 但我不知道在使用角度控制器传递数据时如何包含它。这是我的第一次。非常感谢您的任何建议。这是我的代码。

    我的配置:

    public class CORSFilter implements Filter {
    
        public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
            HttpServletResponse response = (HttpServletResponse) res;
            response.setHeader("Access-Control-Allow-Origin", "*");
            response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE");
            response.setHeader("Access-Control-Max-Age", "3600");
            response.setHeader("Access-Control-Allow-Headers", "x-requested-with, Content-Type");
            chain.doFilter(req, res);
        }
    
        public void init(FilterConfig filterConfig) {}
    
        public void destroy() {}
    
    }
    

    我的安全配置。JAVA

    Configuration
    @EnableWebSecurity
    public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    
        @Autowired
        @Qualifier("customUserDetailsService")
        UserDetailsService userDetailsService;
    
        @Autowired
        PersistentTokenRepository tokenRepository;
    
        @Autowired
        public void configureGlobalSecurity(AuthenticationManagerBuilder auth)
                throws Exception {
            auth.userDetailsService(userDetailsService);
            auth.authenticationProvider(authenticationProvider());
        }
    
        /* This method sets-up the list of accessing page for each role. */
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests()
                    // Request Mapping accessible
                    .antMatchers("/restUser/**") // -------> HERE I INCLUDE THE REQUEST MAPPING
                    // Roles
                    .access("hasRole('ADMIN')").and().formLogin()
                    .loginPage("/login").loginProcessingUrl("/login")
                    .usernameParameter("usernameId").passwordParameter("password").and()
                    .rememberMe().rememberMeParameter("remember-me")
                    .tokenRepository(tokenRepository).tokenValiditySeconds(86400)
                    .and().csrf().and().exceptionHandling()
                    .accessDeniedPage("/Access_Denied");
    
            // Disable spring security
            // http.csrf().disable(); 
    
        }
    
        @Bean
        public PasswordEncoder passwordEncoder() {
            return new BCryptPasswordEncoder();
        }
    
        @Bean
        public DaoAuthenticationProvider authenticationProvider() {
            DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
            authenticationProvider.setUserDetailsService(userDetailsService);
            authenticationProvider.setPasswordEncoder(passwordEncoder());
            return authenticationProvider;
        }
    
        @Bean
        public PersistentTokenBasedRememberMeServices getPersistentTokenBasedRememberMeServices() {
            PersistentTokenBasedRememberMeServices tokenBasedservice = new PersistentTokenBasedRememberMeServices(
                    "remember-me", userDetailsService, tokenRepository);
            return tokenBasedservice;
        }
    
        @Bean
        public AuthenticationTrustResolver getAuthenticationTrustResolver() {
            return new AuthenticationTrustResolverImpl();
        }
    
    }
    

    我的RestController:

    @RestController
    public class UserRestController {
    
        @Autowired
        UserService userService;
    
        // -------------------Retrieve All
        // Users--------------------------------------------------------
    
        @RequestMapping(value = "/restUser", method = RequestMethod.GET)
        public ResponseEntity<List<User>> listAllUsers() {
            List<User> users = userService.findAllUsers();
            if (users.isEmpty()) {
                return new ResponseEntity<List<User>>(HttpStatus.NO_CONTENT);
            }
            return new ResponseEntity<List<User>>(users, HttpStatus.OK);
    
        }
    
        // -------------------Create a
        // User--------------------------------------------------------
    
        @RequestMapping(value = "/restUser", method = RequestMethod.POST)
        public ResponseEntity<Void> createUser(@RequestBody User user,
                UriComponentsBuilder ucBuilder) {
            System.out.println("Creating User " + user.getUsernameId());
    
            // if (userService.isUserExist(user)) {
            // System.out.println("A User with name " + user.getUsername() +
            // " already exist");
            // return new ResponseEntity<Void>(HttpStatus.CONFLICT);
            // }
    
            userService.saveUser(user);
            System.out.println("Fetch Data: " + user);
            HttpHeaders headers = new HttpHeaders();
            headers.setLocation(ucBuilder.path("/restUser/{id}")
                    .buildAndExpand(user.getId()).toUri());
            return new ResponseEntity<Void>(headers, HttpStatus.CREATED);
        }
    
        // -------------------Retrieve Single
        // User--------------------------------------------------------
    
        @RequestMapping(value = "/restUser/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
        public ResponseEntity<User> getUser(@PathVariable("id") int id) {
            System.out.println("Fetching User with id " + id);
            User user = userService.findById(id);
            if (user == null) {
                System.out.println("User with id " + id + " not found");
                return new ResponseEntity<User>(HttpStatus.NOT_FOUND);
            }
    
            System.out.println("Fetch Data: " + user);
            return new ResponseEntity<User>(user, HttpStatus.OK);
        }
    
        // ------------------- Update a User
        // --------------------------------------------------------
    
        @RequestMapping(value = "/restUser/{id}", method = RequestMethod.PUT)
        public ResponseEntity<User> updateUser(@PathVariable("id") int id,
                @RequestBody User user) {
            System.out.println("Updating User " + id);
    
            User currentUser = userService.findById(id);
            //
            // if (currentUser==null) {
            // System.out.println("User with id " + id + " not found");
            // return new ResponseEntity<User>(HttpStatus.NOT_FOUND);
            // }
    
            // currentUser.setUsernameId(user.getUsernameId());
            // currentUser.setFirstName(user.getFirstName());
            // currentUser.setEmail(user.getEmail());
    
            System.out.println("USER: " + user);
            userService.updateUser(user);
            return new ResponseEntity<User>(currentUser, HttpStatus.OK);
        }
    
    }
    

    应用程序。js

    'user strict';
    
    var App = angular.module('myApp', ['ngResource', 'ngAnimate', 'ui.bootstrap']);
    

    用户服务。js

    'use strict';
    
    
    App.factory('User', ['$resource', function ($resource) {
        //$resource() function returns an object of resource class
        return $resource(
                'http://localhost:8080/MavenTry/restUser/:id', 
                {id: '@id'},//Handy for update & delete. id will be set with id of instance
                {
                    update: {
                          method: 'PUT' // To send the HTTP Put request when calling this custom update method.
                    }
    
                }
        );
    }]);
    

    用户控制器。js

    'use strict';
    
    App
            .controller(
                    'UserController',
                    [
                            '$scope',
                            'User',
                            '$uibModal',
                            '$log',
                            function($scope, User, $uibModal, $log) {
                                var self = this;
                                self.user = new User();
    
                                self.users = [];
    
                                //Fetch all user data
                                self.fetchAllUsers = function() {
                                    self.users = User.query();
                                    $log.info('self.users: ', self.users);
                                };
    
                                // Call function fetchAllUsers                          
                                self.fetchAllUsers();
    
    
                                $scope.open = function(id) {
    
                                    $log.info("parameter id: " + id);
                                    $scope.items = [];
    
                                    for (var i = 0; i < self.users.length; i++) {
                                        if (self.users[i].id === id) {
                                            self.user = angular.copy(self.users[i]);
                                            $scope.items = angular
                                                    .copy(self.users[i]);
                                            break;
    
                                        }
                                    }
    
                                    var modalInstance = $uibModal.open({
                                        templateUrl : 'myModal1',
                                        controller : 'ModalInstance',
                                        size : 'lg',
                                        resolve : {
                                            items : function() {
                                                return $scope.items;
                                            }
                                        }
                                    });
                                };
    
                                    self.reset = function() {
                                    self.user = new User();
                                    $scope.myForm.$setPristine(); // reset Form
                                };
    
                            } ]);
    
    
    // Populate modal with data
    App.controller('ModalInstance', function($scope, $uibModalInstance, items,
            $log, User) {
    
        $scope.form = {};
        var myModal = this;
        myModal.user = new User();
    
        myModal.users = [];
    
        myModal.fetchAllUsers = function() {
            myModal.users = User.query();
        };
    
        // Populate DataTable using $GET
        myModal.fetchAllUsers = function() {
            myModal.users = User.query();
            };
    
        // Create user using $POST
        myModal.createUser = function() {
            myModal.user.$save(function() {
            myModal.fetchAllUsers();
            });
        };
    
        // Update $PUT
        myModal.updateUser = function() {
                myModal.user.$update(function() {
                myModal.fetchAllUsers();
            });
        };
    
    
        $scope.userInfo = items;
    
        $scope.submitForm = function() {
            if ($scope.form.userForm.$valid) {
                console.log('CSRF_TOKEN', csrftoken); // Here i retrieve the token from the view page. Dont know how to include this while submiting data
                myModal.user = $scope.userInfo;
    
                // Call function for PUT
                myModal.updateUser();
    
                $uibModalInstance.close('closed');
            } else {
                console.log('userform is not in scope');
            }
    
        };
    
        $scope.cancel = function() {
            $uibModalInstance.dismiss('cancel');
        };
    });
    
    
    //Retrieving CSRF_TOKEN
    var csrftoken = (function() {
        var metas = window.document.getElementsByTagName('meta');
    
        // finding one has csrf token
        for (var i = 0; i < metas.length; i++) {
            if (metas[i].name === "csrf-token") {
                return metas[i].content;
            }
        }
    
    })();
    
    App.constant('CSRF_TOKEN', csrftoken);
    

    在我的视图jsp中,我将csrf令牌存储在

    <meta name="csrf-token" content="${_csrf.token}">
    

    我在angular controller的代码是超级新手,所以任何建议都非常感谢:)。

    2 回复  |  直到 6 年前
        1
  •  1
  •   Lawrence Paje    6 年前

    无论您喜欢jQuery还是纯javascript,都可以通过csrf令牌获得它。然后,您应该将该令牌附加到资源头中。

        2
  •  0
  •   rob    6 年前

    注:我是OP,这个答案实际上解决了这个问题。

    要解决此问题,需要在SecurityConfiguration类中添加以下行:

    /* This method sets-up the list of accessing page for each role. */
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests()
                    // Request Mapping accessible
                    .antMatchers("/restUser/**") // -------> HERE I INCLUDE THE REQUEST MAPPING
                    // Roles
                    .access("hasRole('ADMIN')").and().formLogin()
                    .loginPage("/login").loginProcessingUrl("/login")
                    .usernameParameter("usernameId").passwordParameter("password").and()
                    .rememberMe().rememberMeParameter("remember-me")
                    .tokenRepository(tokenRepository).tokenValiditySeconds(86400)
                    .and().csrf().and().exceptionHandling()
                    .accessDeniedPage("/Access_Denied").and()
                  .addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class).csrf().csrfTokenRepository(csrfTokenRepository());
    
        }    
    
    private CsrfTokenRepository csrfTokenRepository() {
              HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
              repository.setHeaderName("X-XSRF-TOKEN");
              return repository;
            }
    

    以及创建CsrfHeaderFilter。班

    public class CsrfHeaderFilter extends OncePerRequestFilter {
    
        @Override
        protected void doFilterInternal(HttpServletRequest request,
                HttpServletResponse response, FilterChain filterChain)
                throws ServletException, IOException {
            CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class
                    .getName());
            if (csrf != null) {
                Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
                String token = csrf.getToken();
                if (cookie == null || token != null
                        && !token.equals(cookie.getValue())) {
                    cookie = new Cookie("XSRF-TOKEN", token);
                    cookie.setPath("/");
                    response.addCookie(cookie);
                }
            }
            filterChain.doFilter(request, response);
    
        }
    }
    

    通过添加 .addFilterAfter(新的CsrfHeaderFilter(),CsrfFilter。类)。csrf()。csrfTokenRepository(csrfTokenRepository()

    现在POST-and-PUT方法起作用了。我知道我的代码没有那么干净,需要修改以遵循最佳实践。

    参考: https://spring.io/blog/2015/01/12/the-login-page-angular-js-and-spring-security-part-ii