我知道保护REST API是一个广泛评论的主题,但我无法创建符合我的标准的小型原型(我需要确认这些标准是现实的)。如何保护资源以及如何使用Spring安全性有很多选择,我需要澄清我的需求是否切合实际。
我的要求
当前状态
我的REST API运行良好,但现在我需要保护它。当我在寻找解决方案时,我创建了一个javax.servlet.Filter
过滤器:
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
String accessToken = request.getHeader(AUTHORIZATION_TOKEN);
Account account = accountDao.find(accessToken);
if (account == null) {
throw new UnauthorizedException();
}
chain.doFilter(req, res);
}
但是使用javax.servlet.filters
的这个解决方案不能正常工作,因为通过@ControllerAdvice
与Spring servlet dispatcher
进行异常处理存在问题。
我需要的
我想知道这些标准是否切合实际并获得任何帮助,如何开始使用Spring Security保护REST API。我阅读了许多教程(例如Spring Data REST + Spring Security),但所有教程都在非常基本的配置中工作 - 具有凭据的用户在配置中存储在内存中,我需要使用DBMS并创建自己的身份验证器。
请给我一些如何开始的想法。
基于令牌的身份验证 - 用户将提供其凭据并获得唯一且受时间限制的访问令牌。我想管理令牌创建,检查有效性,在我自己的实现中过期。
实际上,使用Filter for token Auth - 在这种情况下最好的方法
最后,您可以通过Spring Data创建CRUD来管理Token的属性,例如过期等。
这是我的令牌过滤器:http://pastebin.com/13WWpLq2
和令牌服务实现
一些REST资源将是公共的 - 根本不需要进行身份验证
这不是问题,您可以通过Spring安全配置管理您的资源,如:.antMatchers("/rest/blabla/**").permitAll()
只有具有管理员权限的用户才能访问某些资源,
看看@Secured
注释到课堂。例:
@Controller
@RequestMapping(value = "/adminservice")
@Secured("ROLE_ADMIN")
public class AdminServiceController {
在授权所有用户后,可以访问其他资源。
回到Spring安全配置,您可以像这样配置您的URL:
http
.authorizeRequests()
.antMatchers("/openforall/**").permitAll()
.antMatchers("/alsoopen/**").permitAll()
.anyRequest().authenticated()
我不想使用基本身份验证
是的,通过令牌过滤器,您的用户将被验证。
Java代码配置(不是XML)
回到上面的话,看看@EnableWebSecurity
。你的课将是:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {}
您必须覆盖configure方法。下面的代码,例如,如何配置匹配器。它来自另一个项目。
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/assets/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.usernameParameter("j_username")
.passwordParameter("j_password")
.loginPage("/login")
.defaultSuccessUrl("/", true)
.successHandler(customAuthenticationSuccessHandler)
.permitAll()
.and()
.logout()
.logoutUrl("/logout")
.invalidateHttpSession(true)
.logoutSuccessUrl("/")
.deleteCookies("JSESSIONID")
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.and()
.csrf();
}
Spring安全性对于为REST URL提供身份验证和授权也非常有用。我们不需要指定任何自定义实现。
首先,您需要在安全配置中指定entry-point-ref到restAuthenticationEntryPoint,如下所示。
<security:http pattern="/api/**" entry-point-ref="restAuthenticationEntryPoint" use-expressions="true" auto-config="true" create-session="stateless" >
<security:intercept-url pattern="/api/userList" access="hasRole('ROLE_USER')"/>
<security:intercept-url pattern="/api/managerList" access="hasRole('ROLE_ADMIN')"/>
<security:custom-filter ref="preAuthFilter" position="PRE_AUTH_FILTER"/>
</security:http>
restAuthenticationEntryPoint的实现可能如下所示。
@Component
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException ) throws IOException {
response.sendError( HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized" );
}
}
在此之后,您需要指定RequestHeaderAuthenticationFilter。它包含RequestHeader键。这主要用于识别用户的身份验证。通常,RequestHeader在进行REST调用时会携带此信息。例如,考虑下面的代码
<bean id="preAuthFilter" class="org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter">
<property name="principalRequestHeader" value="Authorization"/>
<property name="authenticationManager" ref="authenticationManager" />
</bean>
这里,
<property name="principalRequestHeader" value="Authorization"/>
“授权”是传入请求的关键。它包含所需的用户身份验证信息。您还需要配置PreAuthenticatedAuthenticationProvider以满足我们的要求。
<bean id="preauthAuthProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
<property name="preAuthenticatedUserDetailsService">
<bean id="userDetailsServiceWrapper"
class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
<property name="userDetailsService" ref="authenticationService"/>
</bean>
</property>
</bean>
此代码将用于通过身份验证和授权保护REST URL,而无需任何自定义实现。
如需完整代码,请查看以下链接:
我也搜索了很长时间。我正在研究一个类似的项目。我发现Spring有一个通过redis实现会话的模块。它看起来简单实用。我也会加入我的项目。可以提供帮助:
http://docs.spring.io/spring-session/docs/1.2.1.BUILD-SNAPSHOT/reference/html5/guides/rest.html
要验证REST API,有两种方法
1 - 使用application.properties文件中设置的默认用户名和密码进行基本身份验证
2 - 使用数据库(userDetailsService)和实际用户名和密码进行身份验证