我们目前正在使用Spring Boot(1.2.6)编写一个中间件,以向我们的移动/ Web应用程序公开REST API . 中间件没有数据库,并且得到了我们客户的一些远程服务的支持 .
对于Login,我们将用户名/密码和一些参数(ip,用户代理等)发送到远程服务,并获取有关用户(名称,上次登录,布尔更改密码标志等)的一些信息,包括会话ID . 我们写了一些bean,我们在相应的控制器中使用它们:
@RestController
@RequestMapping(value = "/user", produces = "application/json")
public final class UserController {
@Autowired
private UserService userService;
@RequestMapping(value = "/login", method = RequestMethod.POST)
public LoginResponse login(@RequestBody final LoginRequest request, final HttpServletRequest servletRequest) {
final LoginResponse response = new LoginResponse();
final LoginServiceRequest serviceRequest = new LoginServiceRequest();
serviceRequest.setAdditionalRequestData(AdditionalRequestData.getInstance(servletRequest));
serviceRequest.setUsername(request.getUsername());
serviceRequest.setPassword(request.getPassword());
final LoginData serviceResponse = userService.login(serviceRequest);
response.setChangePassword(serviceResponse.isChangePassword());
// setting other params here...
return response;
}
}
据我所知,Spring Security通常依赖于在控制器之前工作的servlet过滤器 . 例如,如果我在配置中启用formLogin,它会启用 UsernamePasswordAuthenticationFilter
,它根据我定义的 AuthenticationManager
bean处理身份验证 . 但是,在这种情况下我需要身份验证响应,并且我们发送以JSON编码的请求参数 . 所以过滤器似乎不适合我们 .
相反,我创建了一个 AuthenticationProvider
和 AuthenticationToken
并将上面的代码改为这样的代码:
@RestController
@RequestMapping(value = "/user", produces = "application/json")
public final class UserController {
@Autowired
private AuthenticationManager auth;
@Autowired
private UserService userService;
@RequestMapping(value = "/login", method = RequestMethod.POST)
public LoginResponse login(@RequestBody final LoginRequest request,
final HttpServletRequest servletRequest) throws ServletException {
final LoginResponse response = new LoginResponse();
final Authentication authenticationToken = new CustomAuthenticationToken(
request.getUserId(),
request.getPassword(),
AdditionalRequestData.getInstance(servletRequest)
);
final LoginData loginData =
((CustomAuthenticationToken) auth.authenticate(authenticationToken)).getLoginData();
response.setChangePassword(loginData.isChangePassword());
// setting other params here...
return response;
}
}
AuthenticationProvider
负责调用 userService.login
方法以及将 AuthenticationToken
设置为 SecurityContext
.
这是我们的安全配置:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomAuthenticationProvider customAuthenticationProvider;
@Autowired
private RestAuthenticationEntryPoint restAuthenticationEntryPoint;
@Override
protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(customAuthenticationProvider);
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(final HttpSecurity http) throws Exception {
// @formatter:off
http
.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.and()
.authorizeRequests()
.antMatchers("/version/**").permitAll()
.anyRequest().hasAnyRole(Constants.ROLE_USER);
// @formatter:on
}
}
这种manuel方法确实有效 . 我们还利用权限(ROLE_USER等..)来授予对不同 endpoints 的访问权限 .
有更好的解决方案吗?当我们这样做时,您认为我们失去了Spring Security的一些功能吗?