我正在尝试从另一个(angularjs)调用一个应用程序(spring-boot应用程序)上的REST端点。这些应用程序正在以下主机和端口上运行。
http://localhost:8080
http://localhost:50029
我也正在使用spring-securityspring- boot应用程序。我可以从HTML应用程序向REST应用程序进行身份验证,但是此后,我仍然无法访问任何REST端点。例如,我有一个定义如下的angularjs服务。
spring-security
adminServices.factory('AdminService', ['$resource', '$http', 'conf', function($resource, $http, conf) { var s = {}; s.isAdminLoggedIn = function(data) { return $http({ method: 'GET', url: 'http://localhost:8080/api/admin/isloggedin', withCredentials: true, headers: { 'X-Requested-With': 'XMLHttpRequest' } }); }; s.login = function(username, password) { var u = 'username=' + encodeURI(username); var p = 'password=' + encodeURI(password); var r = 'remember_me=1'; var data = u + '&' + p + '&' + r; return $http({ method: 'POST', url: 'http://localhost:8080/login', data: data, headers: {'Content-Type': 'application/x-www-form-urlencoded'} }); }; return s; }]);
angularjs控制器如下所示。
adminControllers.controller('LoginController', ['$scope', '$http', 'AdminService', function($scope, $http, AdminService) { $scope.username = ''; $scope.password = ''; $scope.signIn = function() { AdminService.login($scope.username, $scope.password) .success(function(d,s) { if(d['success']) { console.log('ok authenticated, call another REST endpoint'); AdminService.isAdminLoggedIn() .success(function(d,s) { console.log('i can access a protected REST endpoint after logging in'); }) .error(function(d, s) { console.log('huh, error checking to see if admin is logged in'); $scope.reset(); }); } else { console.log('bad credentials?'); } }) .error(function(d, s) { console.log('huh, error happened!'); }); }; }]);
在打给http://localhost:8080/api/admin/isloggedin我的电话上,我得到一个401 Unauthorized。
http://localhost:8080/api/admin/isloggedin
401 Unauthorized
在REST应用程序方面,我有一个CORS过滤器,如下所示。
@Component @Order(Ordered.HIGHEST_PRECEDENCE) public class CORSFilter implements Filter { @Override public void destroy() { } @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletResponse response = (HttpServletResponse) res; HttpServletRequest request = (HttpServletRequest) req; response.setHeader("Access-Control-Allow-Origin", "http://localhost:50029"); response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE"); response.setHeader("Access-Control-Max-Age", "3600"); response.setHeader("Access-Control-Allow-Headers", "X-Requested-With, X-Auth-Token"); response.setHeader("Access-Control-Allow-Credentials", "true"); if(!"OPTIONS".equalsIgnoreCase(request.getMethod())) { chain.doFilter(req, res); } } @Override public void init(FilterConfig config) throws ServletException { } }
我的spring安全配置如下所示。
@Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private RestAuthenticationEntryPoint restAuthenticationEntryPoint; @Autowired private JsonAuthSuccessHandler jsonAuthSuccessHandler; @Autowired private JsonAuthFailureHandler jsonAuthFailureHandler; @Autowired private JsonLogoutSuccessHandler jsonLogoutSuccessHandler; @Autowired private AuthenticationProvider authenticationProvider; @Autowired private UserDetailsService userDetailsService; @Autowired private PersistentTokenRepository persistentTokenRepository; @Value("${rememberme.key}") private String rememberMeKey; @Override protected void configure(HttpSecurity http) throws Exception { http .csrf().disable() .exceptionHandling() .authenticationEntryPoint(restAuthenticationEntryPoint) .and() .authorizeRequests() .antMatchers("/api/admin/**").hasRole("ADMIN") .antMatchers("/", "/admin", "/css/**", "/js/**", "/fonts/**", "/api/**").permitAll() .anyRequest().authenticated() .and() .formLogin() .successHandler(jsonAuthSuccessHandler) .failureHandler(jsonAuthFailureHandler) .permitAll() .and() .logout() .deleteCookies("remember-me", "JSESSIONID") .logoutSuccessHandler(jsonLogoutSuccessHandler) .permitAll() .and() .rememberMe() .userDetailsService(userDetailsService) .tokenRepository(persistentTokenRepository) .rememberMeCookieName("REMEMBER_ME") .rememberMeParameter("remember_me") .tokenValiditySeconds(1209600) .useSecureCookie(false) .key(rememberMeKey); } @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth .authenticationProvider(authenticationProvider); } }
处理程序所做的全部工作就是写出JSON响应,例如{success: true}根据用户是否登录,身份验证失败或注销。在RestAuthenticationEntryPoint如下所示。
{success: true}
RestAuthenticationEntryPoint
@Component public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint { @Override public void commence(HttpServletRequest req, HttpServletResponse resp, AuthenticationException ex) throws IOException, ServletException { resp.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"); } }
关于我缺少或做错的任何想法吗?
import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component;
@Component public class SimpleCORSFilter implements Filter { private final Logger log = LoggerFactory.getLogger(SimpleCORSFilter.class); public SimpleCORSFilter() { log.info("SimpleCORSFilter init"); } @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin")); response.setHeader("Access-Control-Allow-Credentials", "true"); response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE"); response.setHeader("Access-Control-Max-Age", "3600"); response.setHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, remember-me"); chain.doFilter(req, res); } @Override public void init(FilterConfig filterConfig) { } @Override public void destroy() { } }
无需额外定义此过滤器,只需添加此类。Spring将被扫描并为您添加。SimpleCORSFilter。这是示例:spring-enable- cors