কীভাবে ম্যানুয়ালি স্প্রিং সিকিউরিটি / স্প্রিংএমভিসিতে কোনও প্রমাণীকৃত ব্যবহারকারী সেট করবেন


107

কোনও নতুন ব্যবহারকারী 'নতুন অ্যাকাউন্ট' ফর্ম জমা দেওয়ার পরে, আমি সেই ব্যবহারকারীকে ম্যানুয়ালি লগ ইন করতে চাই যাতে তাদের পরবর্তী পৃষ্ঠায় লগইন করতে না হয়।

বসন্ত সুরক্ষা ইন্টারসেপ্টর দিয়ে যাওয়া সাধারণ ফর্ম লগইন পৃষ্ঠাটি ঠিক কাজ করে।

নতুন অ্যাকাউন্ট-ফর্ম নিয়ামকটিতে আমি একটি ব্যবহারকারীনাম পাসওয়ার্ডআউটেন্টিফিকেশন টোকেন তৈরি করছি এবং এটি ম্যানুয়ালি সুরক্ষাকন্টেক্সটে সেট করে দিচ্ছি:

SecurityContextHolder.getContext().setAuthentication(authentication);

সেই একই পৃষ্ঠায় আমি পরে যাচাই করেছিলাম যে ব্যবহারকারীর সাথে লগ ইন হয়েছে:

SecurityContextHolder.getContext().getAuthentication().getAuthorities();

এটি প্রমাণীকরণের আগে আমি নির্ধারিত কর্তৃপক্ষকে ফিরিয়ে দেয়। সবকিছু ঠিক আছে.

কিন্তু যখন এই একই কোডটি আমি লোড করার ঠিক পরের পৃষ্ঠায় কল করা হয়, তখন প্রমাণীকরণের টোকেনটি কেবল ব্যবহারকারী নামবিহীন।

আমি পূর্বের অনুরোধে যে প্রমাণীকরণটি সেট করেছি তা কেন তা পরিষ্কার নয়। কোন চিন্তা?

  • সেশন আইডি সঠিকভাবে সেট আপ না করা নিয়ে এটি কী করতে পারে?
  • এমন কিছু আছে যা সম্ভবত আমার প্রমাণীকরণটি কোনওভাবে ওভাররাইট করছে?
  • প্রমাণীকরণ সংরক্ষণ করার জন্য সম্ভবত আমার আর একটি পদক্ষেপ দরকার?
  • বা কোনও একক অনুরোধের চেয়ে পুরো অধিবেশনে প্রমাণীকরণ ঘোষণা করার জন্য আমার কিছু করার দরকার আছে?

কেবল কিছু চিন্তা সন্ধান করছি যা এখানে কী ঘটছে তা দেখতে আমাকে সহায়তা করতে পারে।


1
আপনাকে আমার উত্তর অনুসরণ করতে পারেন stackoverflow.com/questions/4824395/...
AlexK

2
পাঠক, এই প্রশ্নের উত্তর হুঁশিয়ার যদি তারা আপনাকে যা করতে হবে বলুন: SecurityContextHolder.getContext().setAuthentication(authentication)। এটি কাজ করে এবং সাধারণ, তবে গুরুতর কার্যকারিতা সংক্রান্ত ত্রুটিগুলি রয়েছে যা যদি আপনি কেবল এটি করেন তবে আপনি পূরণ করতে পারেন। আরও তথ্যের জন্য, আমার প্রশ্ন এবং উত্তরটি দেখুন: stackoverflow.com/questions/47233187/…
ছাগল

উত্তর:


62

আমি কিছুটা আগে তোমার মতো একই সমস্যা করেছি। আমি বিশদটি মনে করতে পারি না তবে নিম্নলিখিত কোডটি আমার পক্ষে কাজ করে। এই কোডটি একটি স্প্রিং ওয়েবফ্লো প্রবাহের মধ্যে ব্যবহৃত হয়, তাই অনুরোধকন্টেক্সট এবং বহিরাগত কনটেক্সট ক্লাস। তবে আপনার কাছে যে অংশটি সবচেয়ে বেশি প্রাসঙ্গিক তা হ'ল ডুআউটলগিন পদ্ধতি।

public String registerUser(UserRegistrationFormBean userRegistrationFormBean,
                           RequestContext requestContext,
                           ExternalContext externalContext) {

    try {
        Locale userLocale = requestContext.getExternalContext().getLocale();
        this.userService.createNewUser(userRegistrationFormBean, userLocale, Constants.SYSTEM_USER_ID);
        String emailAddress = userRegistrationFormBean.getChooseEmailAddressFormBean().getEmailAddress();
        String password = userRegistrationFormBean.getChoosePasswordFormBean().getPassword();
        doAutoLogin(emailAddress, password, (HttpServletRequest) externalContext.getNativeRequest());
        return "success";

    } catch (EmailAddressNotUniqueException e) {
        MessageResolver messageResolvable 
                = new MessageBuilder().error()
                                      .source(UserRegistrationFormBean.PROPERTYNAME_EMAIL_ADDRESS)
                                      .code("userRegistration.emailAddress.not.unique")
                                      .build();
        requestContext.getMessageContext().addMessage(messageResolvable);
        return "error";
    }

}


private void doAutoLogin(String username, String password, HttpServletRequest request) {

    try {
        // Must be called from request filtered by Spring Security, otherwise SecurityContextHolder is not updated
        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password);
        token.setDetails(new WebAuthenticationDetails(request));
        Authentication authentication = this.authenticationProvider.authenticate(token);
        logger.debug("Logging in with [{}]", authentication.getPrincipal());
        SecurityContextHolder.getContext().setAuthentication(authentication);
    } catch (Exception e) {
        SecurityContextHolder.getContext().setAuthentication(null);
        logger.error("Failure in autoLogin", e);
    }

}

2
আপনাকে ধন্যবাদ, কোডটি আমাকে সঠিক অঞ্চলে সমস্যার সমাধান করছে তা জানাতে আমাকে সহায়তা করতে খুব সহায়ক। মনে হচ্ছে আমার কাছে ধূমপানের বন্দুক রয়েছে, এটি ম্যানুয়াল প্রমাণীকরণের পরে একটি নতুন সেশন আইডি তৈরি করছে, তবে পুরাতন সেশন আইডিটি এখনও কুকি থেকে সনাক্ত করা হচ্ছে। কেন এখন তা বুঝতে হবে, তবে কমপক্ষে আমি স্পষ্টভাবে ট্র্যাক এ রয়েছি। ধন্যবাদ!
ডেভিড পার্কস

4
এই নির্দেশিকা অনুসরণকারী যে কোনও ব্যক্তিকেও
ডেভিড পার্কস

14
আপনি দয়া করে ব্যাখ্যা করতে পারেন যে আপনি কীভাবে প্রমাণীকরণপ্রাপ্ত
হচ্ছেন প্রভিডার

1
@ s1moner3d আপনি এটি আইওসি -> \ @ স্বীকৃত
হার্টমুট

1
@Configuration public class WebConfig extends WebSecurityConfigurerAdapter { @Bean @Override public AuthenticationManager authenticationProvider() throws Exception { return super.authenticationManagerBean(); } }
slisnychyi

66

আমি অন্য কোনও সম্পূর্ণ সমাধান খুঁজে পাইনি তাই আমি ভেবেছিলাম আমার পোস্ট করব post এটি কিছুটা হ্যাক হতে পারে তবে এটি উপরের সমস্যাটিকে সমাধান করেছে:

public void login(HttpServletRequest request, String userName, String password)
{

    UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(userName, password);

    // Authenticate the user
    Authentication authentication = authenticationManager.authenticate(authRequest);
    SecurityContext securityContext = SecurityContextHolder.getContext();
    securityContext.setAuthentication(authentication);

    // Create a new session and add the security context.
    HttpSession session = request.getSession(true);
    session.setAttribute("SPRING_SECURITY_CONTEXT", securityContext);
}

7
+1 - এটি আমাকে সাহায্য করেছে! আমি SPRING_SECURITY_CONTEXT আপডেট মিস করছি। ... তবে এ কেমন "নোংরা"?
l3dx

12
আপনি কোথা authenticationManagerথেকে পাবেন?
ইসহাক

2
প্রমাণীকরণ ম্যানেজারটি আপনার ক্লাসে এই অটোওয়ার্ডেড অথেনটিকেশনসোসভারসআইএমপিএল প্রমাণীকরণ ম্যানেজারের মতো স্বশিক্ষিত। এবং আপনার এক্সএমএল কনফিগারেশনে অবশ্যই শিমের ইনজেকশন থাকতে হবে, তাই স্প্রিং জানে কী কী ইনজেকশন করতে হয়।

1
অথেনটিকেশনসোর্সআইএমপিএল এর বাস্তবায়ন কোথায়? এই শ্রেণিটি কী ধারণ করে?
Pra_A

3
নতুন অধিবেশন কেন তৈরি করা দরকার? সিকিউরিটি কনটেক্সট হ্যান্ডেল করে না?
ভ্লাদ ম্যানুয়েল মিউরিয়ান 16'16

17

চূড়ান্তভাবে সমস্যার মূলটি বের করে আনে।

আমি যখন ম্যানুয়ালি সুরক্ষা প্রসঙ্গ তৈরি করি তখন কোনও সেশন অবজেক্ট তৈরি হয় না। যখন অনুরোধটি প্রক্রিয়া শেষ করে কেবল তখনই বসন্ত সুরক্ষা প্রক্রিয়া বুঝতে পারে যে সেশনটির অবজেক্টটি শূন্য রয়েছে (যখন এটি অনুরোধটি প্রক্রিয়া করার পরে সেশনে সুরক্ষা প্রসঙ্গটি সংরক্ষণ করার চেষ্টা করে)।

অনুরোধ শেষে স্প্রিং সিকিউরিটি একটি নতুন সেশন অবজেক্ট এবং সেশন আইডি তৈরি করে। তবে এই নতুন সেশন আইডিটি কখনই এটি ব্রাউজারে আসে না কারণ এটি অনুরোধের শেষে ঘটে থাকে, ব্রাউজারটির প্রতিক্রিয়া হওয়ার পরে। পরের অনুরোধটিতে পূর্ববর্তী সেশন আইডি থাকা অবস্থায় এটি নতুন সেশন আইডি (এবং সেইজন্য ম্যানুয়ালি ব্যবহারকারীর উপরে থাকা সুরক্ষা প্রসঙ্গটি) হারাতে পারে causes


4
সত্যিই এটি যে কোনও কিছুর চেয়েও বসন্ত সুরক্ষায় কোনও ডিজাইনের ত্রুটির মত অনুভব করে। অন্যান্য ভাষায় প্রচুর ফ্রেমওয়ার্ক রচিত রয়েছে যাগুলির সাথে এতে কোনও সমস্যা নেই তবে স্প্রিং সিকিউরিটি কেবল ভেঙে যায়।
চুবসন্ডবস

3
এবং সমাধান কি?
s1moner3d

2
এবং সমাধান কি?
থিয়াগো

6

কী চলছে তার আরও ভাল চিত্র পেতে ডিবাগ লগিং চালু করুন।

আপনি বলতে পারেন যে এইচটিটিপি প্রতিক্রিয়াগুলিতে ফিরে আসা শিরোনামগুলি দেখার জন্য ব্রাউজার-সাইড ডিবাগার ব্যবহার করে সেশন কুকিজ সেট করা হচ্ছে কিনা। (অন্যান্য উপায়ও রয়েছে))

একটি সম্ভাবনা হ'ল স্প্রিংসিকিউরিটি নিরাপদ সেশন কুকিজ সেট করছে এবং অনুরোধ করা আপনার পরবর্তী পৃষ্ঠায় একটি "https" URL এর পরিবর্তে একটি "HTTP" URL রয়েছে। (ব্রাউজার কোনও "HTTP" URL- এর জন্য সুরক্ষিত কুকি প্রেরণ করবে না))


ধন্যবাদ এই সমস্ত খুব সহায়ক এবং প্রাসঙ্গিক পরামর্শ ছিল!
ডেভিড পার্কস

5

সার্লেট ২.৪-এ নতুন ফিল্টারিং বৈশিষ্ট্যটি মূলত এই বিধিনিষেধকে হ্রাস করে যে ফিল্টারগুলি কেবলমাত্র অ্যাপ্লিকেশন সার্ভারের দ্বারা আসল অনুরোধ প্রক্রিয়াকরণের আগে এবং পরে অনুরোধ প্রবাহে কাজ করতে পারে। পরিবর্তে, সার্লেলেট ২.৪ ফিল্টার প্রতিটি প্রেরণ পয়েন্টে অনুরোধ প্রেরণের সাথে ইন্টারঅ্যাক্ট করতে পারে। এর অর্থ হ'ল যখন কোনও ওয়েব রিসোর্স অন্য কোনও সংস্থার কাছে কোনও অনুরোধ ফরোয়ার্ড করে (উদাহরণস্বরূপ, কোনও সার্ভলেট অনুরোধটি কোনও জেএসপি পৃষ্ঠায় অনুরোধের জন্য একই অ্যাপ্লিকেশনটিতে ফরোয়ার্ড করে), লক্ষ্যযুক্ত সংস্থান দ্বারা অনুরোধটি পরিচালনা করার আগে একটি ফিল্টার কাজ করতে পারে। এর অর্থ এটিও হ'ল যে কোনও ওয়েব উত্সে অন্য ওয়েব সংস্থানগুলি থেকে আউটপুট বা ফাংশন অন্তর্ভুক্ত করা উচিত (উদাহরণস্বরূপ, একাধিক অন্যান্য জেএসপি পৃষ্ঠাগুলি থেকে আউটপুট সহ একটি জেএসপি পৃষ্ঠা), সার্ভলেট ২.৪ ফিল্টার প্রতিটি অন্তর্ভুক্ত সংস্থানগুলির আগে এবং পরে কাজ করতে পারে। ।

এই বৈশিষ্ট্যটি চালু করতে আপনার প্রয়োজন:

web.xml

<filter>   
    <filter-name>springSecurityFilterChain</filter-name>   
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> 
</filter>  
<filter-mapping>   
    <filter-name>springSecurityFilterChain</filter-name>   
    <url-pattern>/<strike>*</strike></url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
</filter-mapping>

RegistrationController

return "forward:/login?j_username=" + registrationModel.getUserEmail()
        + "&j_password=" + registrationModel.getPassword();

ভাল তথ্য, তবে ইউআরএল-এ ব্যবহারকারীর নাম এবং পাসওয়ার্ড রাখা খারাপ। 1) কোনও পালানোর কাজ শেষ করা হয়নি, সুতরাং বিশেষ অক্ষর সহ একটি ব্যবহারকারীর নাম বা পাসওয়ার্ড ভাঙ্গার সম্ভাবনা রয়েছে, বা আরও খারাপ, সুরক্ষা শোষণকারী ভেক্টর হিসাবে ব্যবহৃত হতে পারে। ২) ইউআরএল-এর পাসওয়ার্ডগুলি খারাপ কারণ ইউআরএলগুলি প্রায়শই ডিস্কে লগ হয় যা সুরক্ষার জন্য বেশ খারাপ - আপনার সমস্ত পাসওয়ার্ড কেবল সেখানে বসে আছে plain
ছাগল

1

আমি একটি এক্সট্রা অ্যাপ্লিকেশন পরীক্ষা করার চেষ্টা করছিলাম এবং সাফল্যের সাথে একটি পরীক্ষা সেটআপ করার পরে প্রমাণীকরণ টোকেন এটি হঠাৎ কোনও সুস্পষ্ট কারণ ছাড়াই কাজ করা বন্ধ করে দিয়েছে।

আমি কাজের উপরের উত্তরগুলি পেতে পারি না তাই আমার সমাধানটি ছিল পরীক্ষার পরিবেশে এই বসন্তের কিছুটা বাদ দেওয়া। আমি বসন্তের চারপাশে এইরকম একটি সিউন চালু করলাম:

public class SpringUserAccessor implements UserAccessor
{
    @Override
    public User getUser()
    {
        SecurityContext context = SecurityContextHolder.getContext();
        Authentication authentication = context.getAuthentication();
        return (User) authentication.getPrincipal();
    }
}

ব্যবহারকারী এখানে একটি কাস্টম টাইপ।

তারপরে আমি এটিকে এমন একটি ক্লাসে মুড়িয়ে দিচ্ছি যা পরীক্ষার কোডটির জন্য বসন্ত স্যুইচ করার জন্য কেবল একটি বিকল্প রয়েছে।

public class CurrentUserAccessor
{
    private static UserAccessor _accessor;

    public CurrentUserAccessor()
    {
        _accessor = new SpringUserAccessor();
    }

    public User getUser()
    {
        return _accessor.getUser();
    }

    public static void UseTestingAccessor(User user)
    {
        _accessor = new TestUserAccessor(user);
    }
}

পরীক্ষার সংস্করণটি ঠিক এর মতো দেখায়:

public class TestUserAccessor implements UserAccessor
{
    private static User _user;

    public TestUserAccessor(User user)
    {
        _user = user;
    }

    @Override
    public User getUser()
    {
        return _user;
    }
}

কলিং কোডে আমি এখনও ডাটাবেস থেকে বোঝা একটি উপযুক্ত ব্যবহারকারী ব্যবহার করছি:

    User user = (User) _userService.loadUserByUsername(username);
    CurrentUserAccessor.UseTestingAccessor(user);

অবশ্যই আপনার যদি সুরক্ষাটি ব্যবহার করা দরকার তবে এটি উপযুক্ত না তবে আমি পরীক্ষার স্থাপনার জন্য কোনও সুরক্ষা সেটআপ নিয়ে চলছি। আমি ভেবেছিলাম অন্য কেউ হয়তো একইরকম পরিস্থিতিতে পড়তে পারে। এটি এমন একটি প্যাটার্ন যা আমি এর আগে স্থিতিশীল নির্ভরতাগুলি উপহাস করার জন্য ব্যবহার করেছি। অন্য বিকল্পটি হ'ল আপনি মোড়কের ক্লাসের স্থিতিশীলতা বজায় রাখতে পারেন তবে কোডের নির্ভরতা আরও সুস্পষ্ট হওয়ায় আপনার কারেন্ট ইউজারএ্যাকসেসরটি প্রয়োজনীয় ক্লাসগুলিতে আপনাকে পাস করতে হবে বলেই আমি এটিকে পছন্দ করি।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.