2015-08-18 7 views
8

प्रतिक्रिया मुझे http प्रतिक्रिया सामग्री हैश के लिए वसंत सुरक्षा बढ़ाने और एक शीर्षलेख के अंदर परिणाम रखने की जरूरत है। मेरा दृष्टिकोण एक सर्वलेट फ़िल्टर बनाना है जो प्रतिक्रिया को पढ़ता है और उचित शीर्षलेख रखता है। फिल्टर एक अलग प्लगइन के माध्यम से वसंत सुरक्षा के साथ पंजीकृत है। कार्यान्वयन बड़े पैमाने पर से लिया गया है।Grails वसंत सुरक्षा, सर्वलेट फिल्टर, और

अंतिम सेटअप क्लाइंट को जेएसओएन आउटपुट करने के लिए नियंत्रक में "रेंडर" का उपयोग करता है जब पूरा सेटअप पूरी तरह से काम करता है। हालांकि, यदि एक ही डेटा "जवाब" के माध्यम से स्वरूपित किया गया है तो 404 ग्राहक को वापस कर दिया जाता है। मैं अंतर को समझाने के लिए एक नुकसान में हूँ।

संदर्भ के लिए सब कुछ है Grails संस्करण 2.3.11 और वसंत सुरक्षा कोर संस्करण 2.0-RC4

मेरी प्लगइन के doWithSpring के माध्यम से फिल्टर रजिस्टर

responseHasher(ResponseHasher) 

SpringSecurityUtils.registerFilter(
       'responseHasher', SecurityFilterPosition.LAST.order - 1) 

मेरे फिल्टर कार्यान्वयन

public class ResponseHasher implements Filter{ 

    @Override 
    public void init(FilterConfig config) throws ServletException { 
    } 

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


     HttpServletResponseCopier wrapper = new HttpServletResponseCopier((HttpServletResponse)response); 

     chain.doFilter(request, wrapper); 
     wrapper.flushBuffer(); 

     /* 
     Take the response, hash it, and set it in a header. for brevity sake just prove we can read it for now 
     and set a static header 
     */ 
     byte[] copy = wrapper.getCopy(); 
     System.out.println(new String(copy, response.getCharacterEncoding())); 
     wrapper.setHeader("foo","bar"); 

    } 

    @Override 
    public void destroy() { 

    } 

} 

HttpServletResponseCopier कार्यान्वयन। स्रोत से एकमात्र परिवर्तन केवल एक के बजाय लिखने के सभी 3 विधि हस्ताक्षर ओवरराइड करना है।

class HttpServletResponseCopier extends HttpServletResponseWrapper{ 

    private ServletOutputStream outputStream; 
    private PrintWriter writer; 
    private ServletOutputStreamCopier copier; 

    public HttpServletResponseCopier(HttpServletResponse response) throws IOException { 
     super(response); 
    } 

    @Override 
    public ServletOutputStream getOutputStream() throws IOException { 
     if (writer != null) { 
      throw new IllegalStateException("getWriter() has already been called on this response."); 
     } 

     if (outputStream == null) { 
      outputStream = getResponse().getOutputStream(); 
      copier = new ServletOutputStreamCopier(outputStream); 
     } 

     return copier; 
    } 

    @Override 
    public PrintWriter getWriter() throws IOException { 
     if (outputStream != null) { 
      throw new IllegalStateException("getOutputStream() has already been called on this response."); 
     } 

     if (writer == null) { 
      copier = new ServletOutputStreamCopier(getResponse().getOutputStream()); 
      writer = new PrintWriter(new OutputStreamWriter(copier, getResponse().getCharacterEncoding()), true); 
     } 

     return writer; 
    } 

    @Override 
    public void flushBuffer() throws IOException { 
     if (writer != null) { 
      writer.flush(); 
     } else if (outputStream != null) { 
      copier.flush(); 
     } 
    } 

    public byte[] getCopy() { 
     if (copier != null) { 
      return copier.getCopy(); 
     } else { 
      return new byte[0]; 
     } 
    } 

    private class ServletOutputStreamCopier extends ServletOutputStream { 

     private OutputStream outputStream; 
     private ByteArrayOutputStream copy; 

     public ServletOutputStreamCopier(OutputStream outputStream) { 
      this.outputStream = outputStream; 
      this.copy = new ByteArrayOutputStream(1024); 
     } 

     @Override 
     public void write(int b) throws IOException { 
      outputStream.write(b); 
      copy.write(b); 
     } 

     @Override 
     public void write(byte[] b,int off, int len) throws IOException { 
      outputStream.write(b,off,len); 
      copy.write(b,off,len); 
     } 

     @Override 
     public void write(byte[] b) throws IOException { 
      outputStream.write(b); 
      copy.write(b); 
     } 

     public byte[] getCopy() { 
      return copy.toByteArray(); 
     } 

    } 
} 

और अंत में वास्तविक आवेदन

@Secured() 
    def myAction() { 
     def thing = Thing.get(1) //thing can be any domain object really. in this case we created thing 1 in bootstap 

     //throws a 404 
     respond(thing) 
     /* 
     works as expected, output is both rendered 
     and sent to system out, header "foo" is in response 
     /* 
     //render thing as JSON 
} 

किसी भी अंतर्दृष्टि में मेरी नियंत्रक विधि की सराहना की होगी के रूप में मुझे समझ नहीं आता क्यों काम करेगा और जवाब नहीं होगा प्रस्तुत करना। इसके अतिरिक्त, मैं इस ज़रूरत को हल करने के लिए अन्य दृष्टिकोणों के लिए खुला हूं यदि मैं जो कोशिश कर रहा हूं वह केवल grails में काम नहीं करेगा। अग्रिम में धन्यवाद।

+0

मुझे लगता है कि यह सामग्री बातचीत के साथ कुछ है: http://grails.github.io/grails-doc/2.3.x/guide/single.html #contentNegotiation। 'MyAction' को पैरामीटर' format = json' के साथ कॉल करने का प्रयास करें या 'स्वीकार करें' अनुरोध शीर्षलेख जोड़ें। – defectus

+0

धन्यवाद। मैंने कोशिश की और इसका कोई असर नहीं पड़ा। मैं एक डीबगर संलग्न कर सकता हूं और देख सकता हूं कि यह कम से कम प्रतिक्रिया विधि के माध्यम से और जेसन रेंडरर में बना रहा है, वैध JSON को लात मार रहा है। मेरा (स्वीकार्य रूप से अज्ञानी) अनुमान है कि समस्या कहीं भी कहीं नीचे है –

+0

आप डिफ़ॉल्ट Grails फ़िल्टर का उपयोग क्यों नहीं करते हैं और 'हेडर()' सेक्शन में नया हेडर डालते हैं? –

उत्तर

1

मैंने सभी परियोजनाओं को grails में रखा, और एक ही समस्या मिली। मुझे कुछ बदलाव करना पड़ा।

रजिस्टर के लिए, मैंने SpringSecurityUtils.clientRegisterFilter विधि का उपयोग किया, क्योंकि मैं Bootstrap.groovy एप्लिकेशन से कर रहा था। इसके अलावा, मैंने resources.groovy

में फ़िल्टर घोषित किया, यह प्रस्तुत करने के साथ काम किया, लेकिन जवाब के साथ 404। तो जवाब को बदल दिया:

respond user, [formats:['json']] 

और यह आपके फ़िल्टर को हटाने के बाद काम करता था। जब भी मैं अपना फ़िल्टर डालता हूं तो मुझे 404 मिल गया और यह action.gsp खोजने की कोशिश कर रहा था।

मैं ServletOutputStreamCopier में एक परिवर्तन किया, close और flush तरीकों के लिए प्रतिनिधियों को लागू करने, और इसके लिए ठीक काम किया प्रस्तुत करना और प्रतिक्रिया:

class HttpServletResponseCopier extends HttpServletResponseWrapper { 

    private ServletOutputStream outputStream; 
    private PrintWriter writer; 
    private ServletOutputStreamCopier copier; 

    public HttpServletResponseCopier(HttpServletResponse response) 
      throws IOException { 
     super(response); 
    } 

    @Override 
    public ServletOutputStream getOutputStream() throws IOException { 
     if (writer != null) { 
      throw new IllegalStateException(
        "getWriter() has already been called on this response."); 
     } 

     if (outputStream == null) { 
      outputStream = getResponse().getOutputStream(); 
      copier = new ServletOutputStreamCopier(outputStream); 
     } 

     return copier; 
    } 

    @Override 
    public PrintWriter getWriter() throws IOException { 
     if (outputStream != null) { 
      throw new IllegalStateException(
        "getOutputStream() has already been called on this response."); 
     } 

     if (writer == null) { 
      copier = new ServletOutputStreamCopier(getResponse() 
        .getOutputStream()); 
      writer = new PrintWriter(new OutputStreamWriter(copier, 
        getResponse().getCharacterEncoding()), true); 
     } 

     return writer; 
    } 

    @Override 
    public void flushBuffer() throws IOException { 
     if (writer != null) { 
      writer.flush(); 
     } else if (outputStream != null) { 
      copier.flush(); 
     } 
    } 

    public byte[] getCopy() { 
     if (copier != null) { 
      return copier.getCopy(); 
     } else { 
      return new byte[0]; 
     } 
    } 

    private class ServletOutputStreamCopier extends ServletOutputStream { 

     private OutputStream outputStream; 
     private ByteArrayOutputStream copy; 

     public ServletOutputStreamCopier(OutputStream outputStream) { 
      this.outputStream = outputStream; 
      this.copy = new ByteArrayOutputStream(1024); 
     } 

     @Override 
     public void write(int b) throws IOException { 
      outputStream.write(b); 
      copy.write(b); 
     } 

     @Override 
     public void write(byte[] b, int off, int len) throws IOException { 
      outputStream.write(b, off, len); 
      copy.write(b, off, len); 
     } 

     @Override 
     public void write(byte[] b) throws IOException { 
      outputStream.write(b); 
      copy.write(b); 
     } 

     @Override 
     public void flush() throws IOException { 
      outputStream.flush(); 
      copy.flush(); 
     } 

     @Override 
     public void close() throws IOException { 
      outputStream.close(); 
      copy.close(); 
     } 

     public byte[] getCopy() { 
      return copy.toByteArray(); 
     } 

    } 
} 

मैं जवाब कार्यान्वयन विवरण के माध्यम से जाना नहीं था, लेकिन मैं इसे लगता है कुछ भ्रम प्राप्त करें क्योंकि इसमें फ्लश या क्लोज़ करने का कोई तरीका नहीं है, और जेसन को प्रस्तुत करने के बजाय दृश्य को कॉल करने में फॉलबैक है।

मुझे पता है कि यह थोड़ा देर हो चुकी है, लेकिन अब यह काम कर रही है।

resources.groovy

beans = { 

    responseHasher(ResponseHasher){ 

    } 

} 

बूटस्ट्रैप।ग्रूवी

def init = { servletContext -> 

    . 

    SpringSecurityUtils.clientRegisterFilter('responseHasher', SecurityFilterPosition.LAST.order - 1) 

} 

बेस्ट, एदेर

संबंधित मुद्दे