我正在尝试使用从角度控制器到REST控制器的模态提交数据。 PUT,GET,POST 方法工作代码仅在CSRF 消除时有效,但当我启用 CSRF时,PUT和POST无法正常工作。我检查了控制台日志,并说它是 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() {}
}
My SecurityConfiguration.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);
}
}
App.js
'user strict';
var App = angular.module('myApp', ['ngResource', 'ngAnimate', 'ui.bootstrap']);
user_service.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.
}
}
);
}]);
user_controller.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}">
我在角度控制器的代码是超级新手所以任何建议都非常感激:)。
答案 0 :(得分:0)
你可以获得那个你更喜欢jQuery或普通javascript的csrf-token。然后,您应该将该标记附加到资源标题中。
答案 1 :(得分:0)
注意:我是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.class
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(new CsrfHeaderFilter(),CsrfFilter.class).csrf()。csrfTokenRepository(csrfTokenRepository()
现在POST和PUT方法有效。我知道我的代码不是很干净,需要修改才能遵循最佳实践。
参考:https://spring.io/blog/2015/01/12/the-login-page-angular-js-and-spring-security-part-ii