31 Mayıs 2018 Perşembe

SpringSecurity PasswordEncoder Arayüzü - Deprecated Kullanmayın

Giriş
Bu arayüz deprecate edildi. org.springframework.security.crypto.password.PasswordEncoder arayüzünü kullanmak lazım

PasswordEncoder Arayüzü
Giriş
Şu satırı dahil ederiz.
import org.springframework.security.authentication.encoding.PasswordEncoder;
Bu arayüz AuthenticationProvider nesnesine geçilir. AuthenticationProvider  nesneleri de ProviderManager nesnesine geçilir.

Md5PasswordEncoder Sınıfı
Şu satırı dahil ederiz.
import org.springframework.security.authentication.encoding.Md5PasswordEncoder;
constructor
Şöyle yaparız
@Bean
public PasswordEncoder passwordEncoder(){
  return new MD5PasswordEncoder();
}
encodePassword metodu
Şöyle yaparız.
@Override
public String encode(CharSequence rawPassword) {
  return new Md5PasswordEncoder().encodePassword(rawPassword.toString(),MY_SALT);
}
ShaPasswordEncoder Sınıfı
XML ile tanımlamak için şöyle yaparız.
<beans:bean id="passwordEncoder"   class="org.springframework.security.authentication.encoding.ShaPasswordEncoder">
  <beans:constructor-arg value="256" />
    <beans:property name="encodeHashAsBase64" value="true" />
</beans:bean>

SpringSecurity ProviderManager Sınıfı

Giriş
AuthenticationManager arayüzünden kalıtır. Kendisine liste olarak verilen List<AuthenticationProvider> listesi üzerinde dolaşarak kullanıcıyı doğrulamaya çalışır.

Açıklaması şöyle
An AuthenticationProvider implementation takes care of verifying an authentication request.

By default Spring Security uses ProviderManager class which delegates to a list of configured AuthenticationProvider(s), each of which is queried to see if it can perform the authentication.

XML Tanımlama
Şöyle yaparız.
<authentication-manager alias="authenticationManager">
   <authentication-provider user-service-ref="userDetailsService">
     <password-encoder hash="sha-256" base64="true">
       <salt-source user-property="salt" />
      </password-encoder>
   </authentication-provider>
 </authentication-manager>

SpringStomp @MessageMapping Anotasyonu - Stomp İstemcisi Tarafından Gönderilen JSON Mesajını Okur

Giriş
Şu satırı dahil ederiz
import org.springframework.messaging.handler.annotation.MessageMapping;
Örnek
Şöyle yaparız.
@MessageMapping("${my.topic}")
public void receiveCommand(Message content) {
    log.info("Received command: " + content);
}
Örnek  - @SendTo
Şöyle yaparız
@Controller
public class ChatController {

  @MessageMapping("/chat.register")
  @SendTo("/topic/public")
  public ChatMessage register(@Payload ChatMessage chatMessage,
SimpMessageHeaderAccessor headerAccessor) {
    headerAccessor.getSessionAttributes().put("username", chatMessage.getSender());
    return chatMessage;
  }

  @MessageMapping("/chat.send")
  @SendTo("/topic/public")
  public ChatMessage sendMessage(@Payload ChatMessage chatMessage) {
    return chatMessage;
  }
}
Örnek - @SendTo
Şu satırı dahil ederiz
import org.springframework.messaging.handler.annotation.SendTo;
1. Broker açılırken enableSimpleBroker() metodunda tüm kullanıcılara göndermek için "/topic", bazı kullanıcılara göndermek için "/queue" şeklinde ayarlanmalıdır. Açıklaması şöyle
... there are two destination prefixes defined: topic and queue. They follow the convention that destinations for messages to be carried on to all subscribed clients via the pub-sub model should be prefixed with topic. On the other hand, destinations for private messages are typically prefixed by queue.
2. Broker açılırken setApplicationDestinationPrefixes() metoduna "/app" değeri geçilir. Bu parametrenin açıklaması şöyle. Tarayıcı mesajı "/app/hello" adresine gönderir.
Defines the prefix app that is used to filter destinations handled by methods annotated with @MessageMapping which you will implement in a controller. The controller, after processing the message, will send it to the broker.
Broker yaratmak için AbstractWebSocketMessageBrokerConfigurer yazısına bakabilirsiniz

3. @SendTo("/topic/greetings") şeklinde olmalıdır. Tarayıcıların "/topic/greetings" adresini dinliyor olması gerekir

Şöyle yaparız. Burada @SendTo ile metod sonucunda döndürülen Greeting nesnesi tüm kullanıcılara gönderiliyor. Tarayıcıların "/topic/greetings" adresini dinliyor olması gerekir. Ayrıca HelloMessage ve Greeting sınıflarının JSON'a dönüştürülebiliyor olması gerekir.
@Controller
public class GreetingController {

  @MessageMapping("/hello")
  @SendTo("/topic/greetings")
  public Greeting greeting(HelloMessage message) throws InterruptedException {
    return new Greeting("Hello, " + message.getName() + "!");
  }
}
Broker şöyle yaratılır. Tarayıcı mesajı "/app/hello" adresine gönderir.
@Configuration
@EnableWebSocketMessageBroker
public class HelloWebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

  @Override
  public void configureMessageBroker(MessageBrokerRegistry config) {
    config.enableSimpleBroker("/topic");
    config.setApplicationDestinationPrefixes("/app");
  }

  public void registerStompEndpoints(StompEndpointRegistry registry) {
    registry.addEndpoint("/hello").withSockJS();
  }
}
Eğer @SendTo kullanmak istemiyorsak şu satırı dahil ederiz
import org.springframework.messaging.simp.SimpMessagingTemplate;
Şöyle yaparız
@Autowired
private SimpMessagingTemplate template;

template.convertAndSend("/topic/greetings", "...");
Örnek - @SendToUser
Açıklaması şöyle. Yani istemcinin önce login olması gerekir.
Spring makes sending private messages a lot easier. We only need to annotate a Controller’s method with @SendToUser. Then, this destination will be handled by UserDestinationMessageHandler, which relies on a session identifier. On the client-side, when a client subscribes to a destination prefixed with /user, this destination is transformed into a destination unique for this user. On the server-side, a user destination is resolved based on a user’s Principal.
Şöyle yaparız. Tarayıcının "/user/queue/greetings" adresini dinliyor olması gerekir.
@MessageMapping("/greetings")
@SendToUser("/queue/greetings")
public String reply(@Payload String message, Principal user) {
 return  "Hello " + message;
}

30 Mayıs 2018 Çarşamba

SpringContext @Conditional Anotasyonu - Condition Nesnesi True İse Bean Yaratılır

Giriş
Condition arayüzünden kalıtan bir sınıf kodlarız. Bu sınıfı @Conditional ile birlikte kullanırız. Eğer Condition sınıfımız true dönerse bean yaratılır

Hazır gelen Condition nesneleri şöyle
- OnPropertyCondition

@Conditional vs @ConditionalOnBean
Açıklaması şöyle. Önce @ConditionalOnBean çalışır ve bean yaratılmasını kontrol eder. Sonra @Conditional çalışır ve bean'i kaydeder
While @ConditionalOnBean might appear similar to @Conditional, they operate at different phases of the application context lifecycle. @ConditionalOnBean checks conditions during bean creation, whereas @Conditional evaluates conditions before the bean definition is registered.
Condition Arayüzü
public interface Condition {
  boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}
Açıklaması şöyle
ConditionContext: Provides context information during the evaluation, including details about the bean factory, environment, and class loader.
AnnotatedTypeMetadata: Offers metadata of the annotated element, which can be a class, method, or field.
Örnek - System Property
Şöyle yaparız
public class MySimpleCondition implements Condition {
  @Override
  public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
    String enabled = System.getProperty("enableMyBean");
    return "true".equalsIgnoreCase(enabled);
  }
}
Örnek - Environment Property
Şöyle yaparız
public class CustomPropertyCondition implements Condition {
  @Override
  public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
    Environment env = context.getEnvironment();
    return env.containsProperty("my.custom.property");
  }
}
Örnek - Profile + Environment Property
Şöyle yaparız
public class ProfileAndPropertyCondition implements Condition {
  @Override
  public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
    Environment env = context.getEnvironment();
    return env.acceptsProfiles("production") 
      && env.containsProperty("enableSpecialFeature");
  }
}
Örnek - Annotation
Şöyle yaparız. Burada @Conditional anotasyonunu kullanıldığı yerdeki diğer anotasyonlara erişiliyor
public class RoleBasedCondition implements Condition {
  @Override
  public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
    Map<String, Object> attributes = metadata
      .getAnnotationAttributes(RoleConditional.class.getName());
    String requiredRole = (String) attributes.get("value");
    
    // Your logic to check if the current user has the required role
    return checkUserRole(requiredRole);
  }
  
  private boolean checkUserRole(String requiredRole) {
    // Custom logic to check user role
    return true; // Or false, based on your evaluation
  }
}
@Conditional Anotasyonu Kullanımı
1. Bu anotasyon sınıf veya metod seviyesinde kullanılabilir
2. Bu anotasyon birden fazla Condition nesnesi alabilir

Örnek - Sınıf Seviyesi
Elimizde şöyle bir kod olsun
public class StopWatchOnOffCondition implements Condition {
  @Override
  public boolean matches(ConditionContext context, AnnotatedTypeMetadata arg1) {
    ...
  }
}
Şöyle yaparız.
@Conditional(value = { StopWatchOnOffCondition.class })
@Service
public class StopWatchService {...}
Örnek - Sınıf Seviyesi ve Sınıf İçinde Beanler
Elimizde şöyle bir kod olsun. Burada Condition false ise sınıf içindeki bean'ler de yaratılmaz. Yani @KafkaListener ve @Scheduled çalışmaz.
@Component
@Conditional(MessageQueueEnabledCondition.class)
public class MyMessageListener {

  @KafkaListener(topics = "myTopic")
  public void listen(String message) {
    // Do something
  }
}

@Component
@Conditional(GeolocationCondition.class)
public class GeolocationBasedScheduler {

  @Scheduled(fixedRate = 5000)
  public void executeTaskBasedOnGeolocation() {
    // Task execution logic
  }
}
Örnek - Çoklu Condition
Şöyle yaparız
@Bean
@Conditional({DatabaseAvailableCondition.class, EmailServiceEnabledCondition.class})
public MyService myService() {
  return new MyServiceImpl();
}
Örnek - Aynı Bean İki Defa - Kullanmayın
Şöyle yaparız. Burada her iki condition da true ise MyService iki defa kaydedilir ancak sonuncusu diğerlerini ezer. Yani myProdService kullanılır
@Bean
@Conditional(OnDevelopmentCondition.class)
public MyService devMyService() {
  return new DevMyService();
}

@Bean
@Conditional(OnProductionCondition.class)
public MyService prodMyService() {
  return new ProdMyService();
}