جاوا و تکنولوژی های آن

java programming language

در این وبلاگ به بررسی نکات موجود در جاوا و تکنولوژی های آن می پردازیم

طبقه بندی موضوعی


Spring Session امکان ساده ای برای مدیریت session در سمت سرور میباشد که محدودیت های Http Session را مرتفع میسازد. این راه حل قابلیت به اشتراک گذاشتن Session ها در بین سرویس های یک cloud بدون اینکه وابسته به یک نود خاص باشند را امکانپذیر میکند علاوه بر این امکان استفاده از چندین Session در مرورگر و header را فراهم میکند 


در این بخش به بررسی session و احراز هویت کاربران با استفاده از Spring Session در وب و با استفاده از JDBC , Gemfire , Redis و یا MongoDB دیتای session را ذخیره و بازیابی خواهیم کرد 


ابتدا وابستگی های مورد نیاز را به pom اضافه میکنیم :

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.4.0.RELEASE</version>
    <relativePath/>
</parent>
 
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session</artifactId>
</dependency>


</dependencies>


بعد تنظیمات ساده ای برای Redis server در Application.properties ست میکنیم :

spring.redis.host=localhost
spring.redis.port=6379


اضافه کردن کلاس Configuration@ برای Spring Session :

@Configuration
@EnableRedisHttpSession
public class SessionConfig extends AbstractHttpSessionApplicationInitializer {
}



تنظیمات پروژه بدون Spring Boot :

اول اضافه کردن وابستگی ها :

<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session</artifactId>
    <version>1.2.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-redis</artifactId>
    <version>1.5.0.RELEASE</version>
</dependency>


حال ساخت کلاس Configuration@ بدون Spring Boot :


@Configuration
@EnableRedisHttpSession
public class SessionConfig extends AbstractHttpSessionApplicationInitializer {
    @Bean
    public JedisConnectionFactory connectionFactory() {
        return new JedisConnectionFactory();
    }
}


* همانطور که میبینید تفاوت استفاده از Spring Boot و استفاده نکردن ان بسیار جزیی است و فرقش تنها Spring Boot برای ما JedisConnectionFactory Bean را میسازد ولی وقتی Spring Boot استفاده نکردیم ما خود JedisConnectionFactory را میسازیم



تنظیمات Application :

اضافه کردن  REST Controller :

@RestController
public class SessionController {
    @RequestMapping("/")
    public String helloAdmin() {
        return "hello admin";
    }
}


اضافه کردن تنظیمات امنیتی :

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
 
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth
          .inMemoryAuthentication()
          .withUser("admin").password("password").roles("ADMIN");
    }
 
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
          .httpBasic().and()
          .authorizeRequests()
          .antMatchers("/").hasRole("ADMIN")
          .anyRequest().authenticated();
    }
}

در تنظیمات امنیتی ما یک کاربر داریم و Authentication را از نوع Basic قرار دادیم



تست :

 

ابتدا سرور Redis را آماده میکنیم و دیتای احتمالی ذخیره شده را حذف میکنیم 

public class SessionControllerTest {
 
    private Jedis jedis;
    private TestRestTemplate testRestTemplate;
    private TestRestTemplate testRestTemplateWithAuth;
    private String testUrl = "http://localhost:8080/";
 
    @Before
    public void clearRedisData() {
        testRestTemplate = new TestRestTemplate();
        testRestTemplateWithAuth = new TestRestTemplate("admin", "password", null);
 
        jedis = new Jedis("localhost", 6379);
        jedis.flushAll();
    }
}


بعد سرور Redis را تست میکنیم که آیا دیتایی در ان وجود دارد یا خیر :

@Test
public void testRedisIsEmpty() {
    Set<String> result = jedis.keys("*");
    assertEquals(0, result.size());
}


حالا تست میکنیم که آیا هنگامی که یک کاربر unauthenticate درخواست غیر مجازی را ارسال میکند توسط Spring Security کد 401 ارسال میشود یا خیر :

@Test
public void testUnauthenticatedCantAccess() {
    ResponseEntity<String> result = testRestTemplate.getForEntity(testUrl, String.class);
    assertEquals(HttpStatus.UNAUTHORIZED, result.getStatusCode());
}


حالا تست نهایی را برای احراز هویت و دریافت Authentication Token انجام میدهیم :


- ابتدا صحت احراز هویت Admin را بررسی میکنیم که آیا موفقیت آمیز بوده است یا خیر 

- بعد مقدار session را از Response Header دریافت میکنیم و از آن برای احراز هویت ثانویه استفاده میکنیم و اگر معتبر بود کلیه دیتا های Redis را پاک میکنیم 

- در آخر یک درخواست دیگر ارسال میکنیم تا تایید کنیم که کاربر ما logout شده است و دیگر احراز هویت و session آن معتبر نیست 


@Test
public void testRedisControlsSession() {
    ResponseEntity<String> result = testRestTemplateWithAuth.getForEntity(testUrl, String.class);
    assertEquals("hello admin", result.getBody()); //login worked
 
    Set<String> redisResult = jedis.keys("*");
    assertTrue(redisResult.size() > 0); //redis is populated with session data
 
    String sessionCookie = result.getHeaders().get("Set-Cookie").get(0).split(";")[0];
    HttpHeaders headers = new HttpHeaders();
    headers.add("Cookie", sessionCookie);
    HttpEntity<String> httpEntity = new HttpEntity<>(headers);
 
    result = testRestTemplate.exchange(testUrl, HttpMethod.GET, httpEntity, String.class);
    assertEquals("hello admin", result.getBody()); //access with session works worked
 
    jedis.flushAll(); //clear all keys in redis
 
    result = testRestTemplate.exchange(testUrl, HttpMethod.GET, httpEntity, String.class);
    assertEquals(HttpStatus.UNAUTHORIZED, result.getStatusCode());
    //access denied after sessions are removed in redis
}









نظرات  (۰)

هیچ نظری هنوز ثبت نشده است

ارسال نظر

ارسال نظر آزاد است، اما اگر قبلا در بیان ثبت نام کرده اید می توانید ابتدا وارد شوید.
شما میتوانید از این تگهای html استفاده کنید:
<b> یا <strong>، <em> یا <i>، <u>، <strike> یا <s>، <sup>، <sub>، <blockquote>، <code>، <pre>، <hr>، <br>، <p>، <a href="" title="">، <span style="">، <div align="">
تجدید کد امنیتی