APIを備えたサーバーがあります。サーバーは Spring Security によって保護されています。
リクエスト パラメータでトークンを使用して、外部アプリケーションから API にアクセスしたい
まず、ユーザーはトークンを提供するサービスにアクセスし、このトークンを使用して API にアクセスします。
しかし、標準の Spring Security ソリューションを介して API への以前のアクセスを保持したいと考えています。
どうすればこれを実装できますか?
APIを備えたサーバーがあります。サーバーは Spring Security によって保護されています。
リクエスト パラメータでトークンを使用して、外部アプリケーションから API にアクセスしたい
まず、ユーザーはトークンを提供するサービスにアクセスし、このトークンを使用して API にアクセスします。
しかし、標準の Spring Security ソリューションを介して API への以前のアクセスを保持したいと考えています。
どうすればこれを実装できますか?
私はより簡単な方法を見つけました:
私のソリューションはトークン認証とフォーム認証で機能しますが、必要に応じてそれらのいずれかを簡単に無効にすることができます。
私のフィルターは Roman のフィルターに似ていますが、ユーザーが特定のリソースにアクセスできるかどうかを確認する必要はなく、ログアウトも処理されません -> springSecurity に渡されます。
認証フィルター:
public class TokenAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
private static final String SECURITY_TOKEN_KEY = "token";
private static final String SECURITY_TOKEN_HEADER = "X-Token";
public TokenAuthenticationFilter() {
super( "/" );
}
@Override
public void doFilter( ServletRequest req, ServletResponse res, FilterChain chain ) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String token = request.getParameter( SECURITY_TOKEN_KEY );
// or this.token = request.getHeader(SECURITY_TOKEN_HEADER);
if ( token != null ) {
Authentication authResult;
try {
authResult = attemptAuthentication( request, response, token );
if ( authResult == null ) {
notAuthenticated( request, response, new LockedException( "User Not found" ) );
return;
}
} catch ( AuthenticationException failed ) {
notAuthenticated( request, response, failed );
return;
}
try {
successfulAuthentication( request, response, chain, authResult );
return;
} catch ( NestedServletException e ) {
logger.error( e.getMessage( ), e );
if ( e.getCause( ) instanceof AccessDeniedException ) {
notAuthenticated( request, response, new LockedException( "Forbidden" ) );
return;
}
}
}
chain.doFilter( request, response );// return to others spring security filters
}
public void notAuthenticated( HttpServletRequest request, HttpServletResponse response, AuthenticationException failed ) throws IOException {
response.sendRedirect( "http://www.google.ro" );
// unsuccessfulAuthentication( request, response, failed );
}
public Authentication attemptAuthentication( HttpServletRequest request, HttpServletResponse response, String token ) throws AuthenticationException, IOException, ServletException {
AbstractAuthenticationToken userAuthenticationToken = authUserByToken( token );
if ( userAuthenticationToken == null )
throw new AuthenticationServiceException( MessageFormat.format( "Error | {0}", "Bad Token" ) );
return userAuthenticationToken;
}
private AbstractAuthenticationToken authUserByToken( String tokenRaw ) {
AbstractAuthenticationToken authToken = null;
try {
// check your input token, identify the user
// if success create AbstractAuthenticationToken for user to return
// eg:
// authToken = new UsernamePasswordAuthenticationToken( username, userHash, userAuthorities );
// authToken = new UsernamePasswordAuthenticationToken( tokenRaw, authToken, )
logger.info( "token received = " + tokenRaw );
// obtain user by your methods
// if ( user != null ) {
// SecurityUser securityUser = new SecurityUser( user );
// return new PreAuthenticatedAuthenticationToken( securityUser, securityUser.getPassword( ), securityUser.getAuthorities( ) );
// }
} catch ( Exception e ) {
logger.error( "Error during authUserByToken", e );
}
return authToken;
}
@Override
protected void successfulAuthentication( HttpServletRequest request, HttpServletResponse response, Authentication authResult ) throws IOException, ServletException {
SecurityContextHolder.getContext( ).setAuthentication( authResult );
new CustomAuthenticationSuccessHandler( ).onAuthenticationSuccess( request, response, authResult );
}
@Override
public Authentication attemptAuthentication( HttpServletRequest request, HttpServletResponse response ) throws AuthenticationException, IOException, ServletException {
logger.error( "No TOKEN PROVIDED" );
return null;
}
}
このフィルターをマップするために必要なのは、springSecurity(addFilterBefore) で構成することだけです。これは、サーブレット構成でマップする必要はありません。
http.authorizeRequests( ).antMatchers( "/login*" ).permitAll( );
http.authorizeRequests( ).antMatchers( "/register*" ).permitAll( );
http.authorizeRequests( ).antMatchers( "/admin/**" ).hasAnyAuthority( "ROLE_ADMIN", "ROLE_USER" );//
http.authorizeRequests( ).and( ).formLogin( )//
.loginPage( "/login" )//
.successHandler( successHandler( ) )//
.failureUrl( "/login?error" ).permitAll( )//
.and( ).logout( )//
.logoutUrl( "/logout" ).logoutSuccessUrl( "/login?logout" ).permitAll( )//
.and( ).rememberMe( ).key( applicationName + "_key" ).tokenValiditySeconds( 2419200 ); // remember me for 2 weeks
http.addFilterBefore( new TokenAuthenticationFilter( ), AnonymousAuthenticationFilter.class );