2017-07-26 83 views
1

我目前正在为我的大学开发Web应用程序。大学为我提供授权服务器。春季安全 - 一个REST API - 两种不同的身份验证

我使用REST API为我的角度前端数据。在后端我使用弹簧引导+弹簧安全

我使用此URL:/分类登录登录,所以当用户访问此URL时,他被重定向到授权服务器,登录,...,你知道它是怎么回事。如果我正确理解这一点,结果是JSESSIONID保存在浏览器cookie中,应用程序通过JSESSIONID识别用户并从其会话中获取用户名。

我需要做的是使用其他Web应用程序相同的REST API,让用户在完全不同的应用程序日志,其他的应用程序得到他的访问令牌,然后使用此令牌来访问我的API。问题是我的应用只能通过JSESSIONID识别用户。所以我的问题是,如何设置spring安全性来首先通过jsessionid检查用户,如果不通过访问令牌进行检查。

由于任何人回答。

Java代码:

@SpringBootApplication 
@EnableOAuth2Sso 
@ComponentScan 
@ImportResource({"classpath:classification-connector.xml", "classpath:classification-security.xml"}) 
public class Application extends WebSecurityConfigurerAdapter { 

@Override 
public void configure(HttpSecurity http) throws Exception { 
    http.logout().and().antMatcher("/**").authorizeRequests() 
      .antMatchers("/classification-login").authenticated() 
      .anyRequest().permitAll(); 
} 

public static void main(String[] args) { 
    SpringApplication.run(Application.class, args); 
} 
} 

配置在YAML:

debug: true 
security: 
    user: 
    password: none 
    oauth2: 
    client: 
     accessTokenUri: https://xxx/oauth/token 
     userAuthorizationUri: https://xxx/oauth/authorize 
     clientId: supersecret 
     clientSecret: supersecret 
     scope: read 

    resource: 
     tokenInfoUri: https://xxx/oauth/check_token 

回答

1

,我发现自己的答案与此文章的帮助:http://automateddeveloper.blogspot.cz/2014/03/securing-your-mobile-api-spring-security.html

也许有这样做的更好的办法,但这里是我的解决方案:

我用了两个结构F尔斯,先由双方客户应用程序和原有网络应用和第二我的登录页面

import org.springframework.context.annotation.Configuration; 
import org.springframework.core.annotation.Order; 
import org.springframework.security.config.annotation.web.builders.HttpSecurity; 
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; 


@Configuration 
@EnableWebSecurity 
@Order(1) 
public class ConfigApi extends WebSecurityConfigurerAdapter { 

     @Override protected void configure(HttpSecurity http) throws Exception { 
      http 
        .antMatcher("/api/**") 
        .csrf() 
        .disable() 
        .authorizeRequests().anyRequest().authenticated().and() 
        .addFilterBefore(new CustomFilter(), BasicAuthenticationFilter.class); 
     } 
} 

首先配置增加了过滤器上的URL的每个请求之前开始accesed资源与/ API/**

import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso; 
import org.springframework.context.annotation.Configuration; 
import org.springframework.core.annotation.Order; 
import org.springframework.security.config.annotation.web.builders.HttpSecurity; 
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 

@Configuration 
@EnableWebSecurity 
@EnableOAuth2Sso 

@Order(2) 
public class ConfigLogin extends WebSecurityConfigurerAdapter { 


     @Override 
     protected void configure(HttpSecurity http) throws Exception { 
      http 
        .csrf() 
        .disable() 
        .authorizeRequests() 
        .antMatchers("/classification-login").authenticated(); 
     } 
} 

第二个配置表示,对url/classification-login的请求需要进行身份验证,但不添加任何过滤器。这意味着,用户将被重定向到授权服务器,在那里,他登录和春季安全会(使用JSESSIONID)

import org.springframework.beans.factory.annotation.Value; 
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 
import org.springframework.security.core.GrantedAuthority; 
import org.springframework.security.core.authority.SimpleGrantedAuthority; 
import org.springframework.security.core.context.SecurityContextHolder; 
import org.springframework.security.core.context.SecurityContextImpl; 
import org.springframework.security.oauth2.provider.OAuth2Authentication; 
import org.springframework.security.oauth2.provider.OAuth2Request; 
import org.springframework.web.client.RestTemplate; 
import org.springframework.web.filter.GenericFilterBean; 

import javax.servlet.FilterChain; 
import javax.servlet.ServletException; 
import javax.servlet.ServletRequest; 
import javax.servlet.ServletResponse; 
import javax.servlet.http.HttpServletRequest; 
import java.io.IOException; 
import java.util.*; 

public class CustomFilter extends GenericFilterBean { 


    @Value("${security.oauth2.client.clientId}") 
    private String clientId; 
    @Value("${security.oauth2.resource.tokenInfoUri}") 
    private String checkToken; 
    @Value("${security.oauth2.client.scope}") 
    private String scope; 

     @Override 
     public void doFilter(
       ServletRequest request, 
       ServletResponse response, 
       FilterChain chain) throws IOException, ServletException { 

        try { 
         final HttpServletRequest httpServletRequest = (HttpServletRequest) request; 
         final String authorization = httpServletRequest.getHeader("Authorization"); 
         final String token = authorization.replace("Bearer ", ""); 

         //Here I verify the user by token sent in headers (using tokenInfoUri of my authorization server) 
         final RestTemplate restTemplate = new RestTemplate(); 
         final TokenInfo tokenInfo = restTemplate.getForObject(checkToken + "?token=" + token, TokenInfo.class); 
         final String userName = tokenInfo.getUserName(); 

         final Set<String> scopes = new HashSet<>(); 
         scopes.add(scope); 
         final OAuth2Request oAuth2Request = new OAuth2Request(Collections.<String, String>emptyMap(), clientId, null, true, scopes, null, null, null, null); 
         final List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>(); 
         authorities.add(new SimpleGrantedAuthority("ROLE_USER")); 
         final UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(userName, null, authorities); 
         final OAuth2Authentication oAuth2Authentication = new OAuth2Authentication(oAuth2Request, usernamePasswordAuthenticationToken); 
         oAuth2Authentication.setAuthenticated(true); 
         final SecurityContextImpl securityContext = (SecurityContextImpl) SecurityContextHolder.getContext(); 
         securityContext.setAuthentication(oAuth2Authentication); 
        } catch (Exception ignore) { 
         System.out.println(ignore); 
        } 
      chain.doFilter(request, response); 
     } 
} 

这里是我的过滤器,基本上我只是检查头在申请保存在他的会话的认证,阅读令牌并通过令牌对用户进行身份验证。 (如果没有道理,它捕获异常,并继续[可能会做的更好的未来,现在没有时间吧])

结果:

如果用户使用我的webapp他登录使用/ classification-login,然后允许他使用api,因为spring安全将他的身份验证保存在他的会话中。

如果有人想利用他的应用程序,他需要用他的应用程序相同的授权服务器的API,让他的令牌,并通过它在头请求。

如果有人知道一个更好的解决方案随意评论,我花了太多时间在这,所以我不打算进一步调查的任何。