2015-12-20 50 views
11

में स्प्रिंग के लॉगिन/लॉगआउट एपीआई को दस्तावेज करना मैं Spring Boot का उपयोग कर डेमो रीस्ट सेवा विकसित कर रहा हूं जहां उपयोगकर्ता को संचालन के कुछ सबसेट करने के लिए लॉगिन करना है। Swagger UI जोड़ने के बाद (springfox लाइब्रेरी का उपयोग) है कि सरल विन्यास के साथ:स्वैगर

@Bean 
public Docket docApi() { 
    return new Docket(DocumentationType.SWAGGER_2) 
      .select() 
       .apis(any()) 
       .paths(PathSelectors.ant("/api/**")) 
       .build() 
      .pathMapping("/") 
      .apiInfo(apiInfo()) 
      .directModelSubstitute(LocalDate.class, String.class) 
      .useDefaultResponseMessages(true) 
      .enableUrlTemplating(true); 
} 

मैं Swagger UI पृष्ठ पर सूचीबद्ध सभी कार्यों के साथ सभी API के साथ खत्म। दुर्भाग्यवश मेरे पास सूचीबद्ध लॉगिन/लॉगआउट एंडपॉइंट्स नहीं हैं।

समस्या यह है कि उस परिचालन का हिस्सा Swagger UI अंतर्निहित रूप (मुझे यह वास्तव में अच्छी सुविधा मिलती है और इसे काम करना चाहती है) के माध्यम से नहीं किया जा सकता है, क्योंकि उपयोगकर्ता लॉग इन नहीं है। क्या उस समस्या का कोई समाधान है ? क्या मैं Swagger में मैन्युअल रूप से कुछ अंतराल परिभाषित कर सकता हूं?

यदि प्रमाण पत्र जमा करने के लिए कोई फॉर्म था (यानी लॉगिन/लॉगआउट एंडपॉइंट्स) मैं उस सुरक्षित अंतराल का उपयोग करने से पहले प्राधिकरण कर सकता था। फिर, Swagger उपयोगकर्ता प्रतिक्रिया से token/sessionid निकाल सकता है और इसे @ApiImplicitParams के माध्यम से परिभाषित कस्टम क्वेरी पैरामीटर पर पेस्ट कर सकता है।

नीचे आप मेरी सुरक्षा विन्यास पा सकते हैं: पार्टी के लिए

@Override 
protected void configure(HttpSecurity http) throws Exception { 
    http 
      .formLogin() 
       .loginProcessingUrl("/api/login") 
       .usernameParameter("username") 
       .passwordParameter("password") 
       .successHandler(new CustomAuthenticationSuccessHandler()) 
       .failureHandler(new CustomAuthenticationFailureHandler()) 
       .permitAll() 
       .and() 
      .logout() 
       .logoutUrl("/api/logout") 
       .logoutSuccessHandler(new CustomLogoutSuccessHandler()) 
       .deleteCookies("JSESSIONID") 
       .permitAll() 
       .and() 
      .csrf() 
       .disable() 
      .exceptionHandling() 
       .authenticationEntryPoint(new CustomAuthenticationEntryPoint()) 
       .and() 
      .authorizeRequests() 
      .and() 
       .headers() 
       .frameOptions() 
       .disable(); 
} 

@Override 
protected void configure(AuthenticationManagerBuilder auth) throws Exception { 
    auth 
      .userDetailsService(userDetailsService) 
      .passwordEncoder(passwordEncoder()); 
} 

उत्तर

6

एक थोड़ी देर हो चुकी है, लेकिन जब से SpringFox प्रलेखन के निर्माण के लिए वसंत सेम पर निर्भर करता है, हम इसे आसानी से हेरफेर कर सकते हैं। उम्मीद है कि यह किसी की मदद कर सकता है!

import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.LinkedList; 
import java.util.List; 

import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.http.HttpMethod; 

import com.fasterxml.classmate.TypeResolver; 
import com.google.common.collect.Multimap; 

import springfox.documentation.builders.ApiListingBuilder; 
import springfox.documentation.builders.OperationBuilder; 
import springfox.documentation.builders.ParameterBuilder; 
import springfox.documentation.schema.ModelRef; 
import springfox.documentation.service.ApiDescription; 
import springfox.documentation.service.ApiListing; 
import springfox.documentation.service.Operation; 
import springfox.documentation.spring.web.plugins.DocumentationPluginsManager; 
import springfox.documentation.spring.web.readers.operation.CachingOperationNameGenerator; 
import springfox.documentation.spring.web.scanners.ApiDescriptionReader; 
import springfox.documentation.spring.web.scanners.ApiListingScanner; 
import springfox.documentation.spring.web.scanners.ApiListingScanningContext; 
import springfox.documentation.spring.web.scanners.ApiModelReader; 

public class FormLoginOperations extends ApiListingScanner 
{ 
    @Autowired 
    private TypeResolver typeResolver; 

    @Autowired 
    public FormLoginOperations(ApiDescriptionReader apiDescriptionReader, ApiModelReader apiModelReader, DocumentationPluginsManager pluginsManager) 
    { 
     super(apiDescriptionReader, apiModelReader, pluginsManager); 
    } 

    @Override 
    public Multimap<String, ApiListing> scan(ApiListingScanningContext context) 
    { 
     final Multimap<String, ApiListing> def = super.scan(context); 

     final List<ApiDescription> apis = new LinkedList<>(); 

     final List<Operation> operations = new ArrayList<>(); 
     operations.add(new OperationBuilder(new CachingOperationNameGenerator()) 
      .method(HttpMethod.POST) 
      .uniqueId("login") 
      .parameters(Arrays.asList(new ParameterBuilder() 
       .name("username") 
       .description("The username") 
       .parameterType("query")    
       .type(typeResolver.resolve(String.class)) 
       .modelRef(new ModelRef("string")) 
       .build(), 
       new ParameterBuilder() 
       .name("password") 
       .description("The password") 
       .parameterType("query")    
       .type(typeResolver.resolve(String.class)) 
       .modelRef(new ModelRef("string")) 
       .build())) 
      .summary("Log in") // 
      .notes("Here you can log in") 
      .build()); 
     apis.add(new ApiDescription("/api/login/", "Authentication documentation", operations, false)); 

     def.put("authentication", new ApiListingBuilder(context.getDocumentationContext().getApiDescriptionOrdering()) 
      .apis(apis) 
      .description("Custom authentication") 
      .build()); 

     return def; 
    } 
} 

प्रतिपादन स्वैगर json:

"/api/login/" : { 
     "post" : { 
     "summary" : "Log in", 
     "description" : "Here you can log in", 
     "operationId" : "loginUsingPOST", 
     "parameters" : [ { 
      "name" : "username", 
      "in" : "query", 
      "description" : "The username", 
      "required" : false, 
      "type" : "string" 
     }, { 
      "name" : "password", 
      "in" : "query", 
      "description" : "The password", 
      "required" : false, 
      "type" : "string" 
     } ] 
     } 
    } 
2

बस एक छोटे से सुधार जोड़ने

एक सेम

@Primary 
@Bean 
public ApiListingScanner addExtraOperations(ApiDescriptionReader apiDescriptionReader, ApiModelReader apiModelReader, DocumentationPluginsManager pluginsManager) 
{ 
    return new FormLoginOperations(apiDescriptionReader, apiModelReader, pluginsManager); 
} 

किसी भी आपरेशन मैन्युअल रूप से जोड़ने के लिए इस्तेमाल किया वर्ग के रूप में यह रजिस्टर। यदि आप वास्तविक POST-request (उदाहरण के लिए swagger-ui के HTML पृष्ठ के माध्यम से) बनाना चाहते हैं, तो आपको मॉर्टन के उत्तर में थोड़ा बदलाव करने की आवश्यकता है।

मोर्टेन के कोड पोस्ट अनुरोध करता है/लॉगिन करने के लिए इस तरह:

http://<hostname>/api/login?username=<user>&password=<password>

लेकिन आप अनुरोध आप इसके साथ एक शरीर पारित करने के लिए जरूरत है एक पोस्ट करना चाहते हैं, बस पैरामीटर क्वेरी नहीं।

@Override 
public Multimap<String, ApiListing> scan(ApiListingScanningContext context) 
{ 
    final Multimap<String, ApiListing> def = super.scan(context); 

    final List<ApiDescription> apis = new LinkedList<>(); 

    final List<Operation> operations = new ArrayList<>(); 
    operations.add(new OperationBuilder(new CachingOperationNameGenerator()) 
     .method(HttpMethod.POST) 
     .uniqueId("login") 
     .parameters(Arrays.asList(new ParameterBuilder() 
      .name("body") 
      .required(true) 
      .description("The body of request") 
      .parameterType("body")    
      .type(typeResolver.resolve(String.class)) 
      .modelRef(new ModelRef("string")) 
      .build())) 
     .summary("Log in") // 
     .notes("Here you can log in") 
     .build()); 
    apis.add(new ApiDescription("/api/login/", "Authentication documentation", operations, false)); 

    def.put("authentication", new ApiListingBuilder(context.getDocumentationContext().getApiDescriptionOrdering()) 
     .apis(apis) 
     .description("Custom authentication") 
     .build()); 

    return def; 
} 

अब हम हमारी पोस्ट अनुरोध के साथ एक शरीर पारित कर सकते हैं: कि ऐसा आप इस तरह नाम body और पैरामीटर प्रकार body साथ पैरामीटर जोड़ना बनाने के लिए,। एक शरीर, JSON हो सकता है उदाहरण के लिए:

{"username":"admin","password":"admin"}

0

तुम बस स्वैगर प्रलेखन उत्पन्न करने के लिए अपने एपीआई में एक नकली लॉगिन और लॉगआउट विधि जोड़ सकते हैं, यह स्वतः ही वसंत सुरक्षा फिल्टर द्वारा ओवरराइड किया जा जाएगा।

@ApiOperation("Login.") 
@PostMapping("/login") 
public void fakeLogin(@ApiParam("User") @RequestParam String email, @ApiParam("Password") @RequestParam String password) { 
    throw new IllegalStateException("This method shouldn't be called. It's implemented by Spring Security filters."); 
} 

@ApiOperation("Logout.") 
@PostMapping("/logout") 
public void fakeLogout() { 
    throw new IllegalStateException("This method shouldn't be called. It's implemented by Spring Security filters."); 
} 
1

आप प्रमाणीकरण API का वर्णन करने वाले इंटरफ़ेस का उपयोग कर सकते हैं।Acutal कार्यान्वयन वसंत सुरक्षा द्वारा प्रदान किया जाता है। (यह इटालो के उत्तर की एक भिन्नता है, जहां एक नकली कार्यान्वयन के बजाय एक इंटरफ़ेस का उपयोग किया जाता है।)

/** 
* Authentication API specification for Swagger documentation and Code Generation. 
* Implemented by Spring Security. 
*/ 
@Api("Authentication") 
@RequestMapping(value = "/", produces = MediaType.APPLICATION_JSON_VALUE) 
public interface AuthApi { 
    /** 
    * Implemented by Spring Security 
    */ 
    @ApiOperation(value = "Login", notes = "Login with the given credentials.") 
    @ApiResponses({@ApiResponse(code = 200, message = "", response = Authentication.class)}) 
    @RequestMapping(value = "/login", method = RequestMethod.POST) 
    default void login(
     @RequestParam("username") String username, 
     @RequestParam("password") String password 
    ) { 
     throw new IllegalStateException("Add Spring Security to handle authentication"); 
    } 

    /** 
    * Implemented by Spring Security 
    */ 
    @ApiOperation(value = "Logout", notes = "Logout the current user.") 
    @ApiResponses({@ApiResponse(code = 200, message = "")}) 
    @RequestMapping(value = "/logout", method = RequestMethod.POST) 
    default void logout() { 
     throw new IllegalStateException("Add Spring Security to handle authentication"); 
    } 
} 
संबंधित मुद्दे