2017-07-26 60 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,讓他的令牌,並通過它在頭請求。

如果有人知道一個更好的解決方案隨意評論,我花了太多時間在這,所以我不打算進一步調查的任何。