我正在使用Basic-Auth保护我的REST api。根据用户传递的正确凭据,控制器负责发送httpOnly
和secure
cookie作为响应。
@GetMapping
@ResponseStatus(value=HttpStatus.OK)
public void loginUser( final HttpServletRequest request ,final HttpServletResponse response) throws UnsupportedEncodingException {
setAuthCookieToResonse(request,response);
}
private void setAuthCookieToResonse(final HttpServletRequest request ,final HttpServletResponse response) throws UnsupportedEncodingException {
String cookieKey = "auth";
String cookieValue = request.getHeader("Authorization");
if (cookieValue != null) {
Cookie cookie = new Cookie(cookieKey, cookieValue);
cookie.setHttpOnly(true);
cookie.setSecure(true);
response.addCookie(cookie);
}
}
因此,现在每个请求都由浏览器发送一个cookie,其中将包含Basic-Auth详细信息。但是问题是,Spring Security如何从Cookie中提取这些凭据?
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {// @formatter:off
httpSecurity
.cors()
.and().authorizeRequests()
.antMatchers("/signup/**").permitAll()
.anyRequest().authenticated()
.and().httpBasic()
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().csrf().disable()
;
}
我的猜测是:
在BasicAuthenticationFilter.class
之前添加过滤器并从cookie
中提取凭证,然后将这些凭证添加到HttpServletRequest
的{{1}}标头中,该标头将传递给spring-security层。但是问题是Authorizaton
没有添加标题的API。
实现此目标的正确方法是什么?
答案 0 :(得分:0)
在遵循this blog之后,我使此工作正常进行。但是我很想听听其他解决方案,尤其是使用一些弹簧配置本身。 Spring是一个非常成熟的框架,它必须(应该)有一些东西可以解决这个普遍的问题。
由于storage.select = function ( items, db, where, sign, whereNew ) {
let that = this;
// preset sql query
let query = `select ${items} from ${db}`;
if ( where && sign && whereNew ) { query += ` where ${where} ${sign} ${whereNew}` };
return new Promise ( function ( resolve, reject ) {
storage.each( query, [], function ( err, row ) {
if ( err ) { reject( err )}
else resolve( row );
})
})
};
const result = storage.select( '*', 'users', 'id', '=', 1 )
.then( row => { l( row ) })
.catch( err => { l( err ) });
没有任何添加新标头的方法,因此我需要创建一个自定义类,该类可以向请求添加新标头,这可以由HttpServletRequest
实现。这是实现。
HttpServletRequestWrapper
在Spring安全之前检查cookie的过滤器:
public final class MutableHttpServletRequest extends HttpServletRequestWrapper {
// holds custom header and value mapping
private final Map<String, String> customHeaders;
public MutableHttpServletRequest(HttpServletRequest request) {
super(request);
this.customHeaders = new HashMap<String, String>();
}
public void putHeader(String name, String value) {
this.customHeaders.put(name, value);
}
public String getHeader(String name) {
// check the custom headers first
String headerValue = customHeaders.get(name);
if (headerValue != null) {
return headerValue;
}
// else return from into the original wrapped object
return ((HttpServletRequest) getRequest()).getHeader(name);
}
public Enumeration<String> getHeaderNames() {
// create a set of the custom header names
Set<String> set = new HashSet<String>(customHeaders.keySet());
// now add the headers from the wrapped request object
Enumeration<String> e = ((HttpServletRequest) getRequest()).getHeaderNames();
while (e.hasMoreElements()) {
// add the names of the request headers into the list
String n = e.nextElement();
set.add(n);
}
// create an enumeration from the set and return
return Collections.enumeration(set);
}
}
最后是安全配置:
public class CheckAuthCookieFilter implements Filter {
private Logger logger = LoggerFactory.getLogger(getClass());
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
MutableHttpServletRequest mutableRequest = new MutableHttpServletRequest(httpServletRequest);
Cookie[] cookies = httpServletRequest.getCookies();
if (cookies != null && cookies.length > 0) {
for (Cookie cookie : cookies) {
logger.debug(cookie.getName() + " : " + cookie.getValue());
if (cookie.getName().equalsIgnoreCase("auth")) {
mutableRequest.putHeader("Authorization", URLDecoder.decode(cookie.getValue(), "utf-8"));
}
}
}
chain.doFilter(mutableRequest, response);
}
}
我的自定义过滤器将在Spring的@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {// @formatter:off
httpSecurity
.cors()
.and().authorizeRequests()
.antMatchers("/signup/**").permitAll()
.anyRequest().authenticated()
.and().httpBasic()
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().csrf().disable()
;
httpSecurity.addFilterBefore(new CheckAuthCookieFilter(), BasicAuthenticationFilter.class);
}
之前运行。如果存在名称为BasicAuthenticationFilter
的cookie(应用程序在成功登录时创建的),则该cookie会保存基本的身份验证凭据。从中提取凭证,并将其添加到auth
的标头中。然后request
将运行并寻找BasicAuthenticationFilter
并继续其正常流程。