JavaRush /Java blogi /Random-UZ /Eslatmalar xizmati misolidan foydalanib, elektron pochta ...

Eslatmalar xizmati misolidan foydalanib, elektron pochta va OAuth2 orqali Spring Security-ga muntazam kirishni joriy qilaylik

Guruhda nashr etilgan
Murojaatimni yozish paytida men foydalanuvchini elektron pochta va ijtimoiy tarmoqlar orqali qanday qilib ro'yxatdan o'tkazishga oid aniq maqolalar etishmasligiga duch keldim. Klassik kirish formasini o'rnatish bo'yicha yaxshi darsliklar bor edi. OAuth2 bo'yicha yaxshi darsliklar bor edi . Ikki usulni qanday birlashtirish haqida jinoiy jihatdan kam ma'lumot bor edi. Qidiruv jarayonida biz amaliy yechim topishga muvaffaq bo'ldik. U o'zini yakuniy haqiqat deb da'vo qilmaydi, lekin u o'z vazifasini bajaradi. Ushbu maqolada men noldan o'xshash Spring Security konfiguratsiyasi bilan eslatma saqlash xizmatini qanday amalga oshirishni ko'rsataman. Notes xizmati misolidan foydalanib, elektron pochta va OAuth2 orqali Spring Security-ga muntazam kirishni joriy qilaylik - 1Eslatma: agar o'quvchi bahor bo'yicha hech bo'lmaganda bir nechta darsliklardan o'tgan bo'lsa yaxshi bo'ladi, chunki e'tibor faqat bahor xavfsizligiga qaratiladi, omborlar, kontrollerlar va boshqalar haqida batafsil tushuntirishlarsiz. Aks holda, allaqachon juda katta maqola chiqadi. ulkan bo'ling. Tarkib
  1. Loyiha yaratish
  2. Ob'ektlar va ilovalar mantig'ini yaratish
    1. Ob'ektlar
    2. Repozitariylar
    3. Kontrollerlar
    4. Sahifalar
  3. Klassik kirish uchun bahor xavfsizligini sozlash
    1. SecurityConfig asosiy konfiguratsiyasi
    2. Shaxsiy foydalanuvchi login
    3. Keling, boshqaruvchini yaxshilaymiz
    4. Ishga tushirish
  4. Spring Security-da Google-dan foydalanib, OAuth2-ni o'rnatish
    1. Filtr konfiguratsiyasi va application.properties
    2. Ilovani Google Cloud Platform bilan ro'yxatdan o'tkazishning muhim jihatlari
    3. CustomUserInfoTokenServices
  5. Loyihaning yakuniy boshlanishi

Loyiha yaratish

Biz start.spring.io saytiga o'tamiz va loyihaning asosini tashkil qilamiz:
  • Web - o'rnatilgan Tomcat-da dasturni ishga tushirish, url xaritalari va shunga o'xshashlar;
  • JPA - ma'lumotlar bazasiga ulanish;
  • Mo'ylov - veb-sahifalarni yaratish uchun ishlatiladigan shablon mexanizmi;
  • Xavfsizlik - ilovalarni himoya qilish. Ushbu maqola aynan shu maqsadda yaratilgan.
Olingan arxivni yuklab oling va uni kerakli papkaga oching. Biz uni IDE-da ishga tushiramiz. Ma'lumotlar bazasini o'zingizning xohishingiz bilan tanlashingiz mumkin. Loyiha uchun ma'lumotlar bazasi sifatida MySQL dan foydalanaman, shuning uchun <dependencies> blokidagi pom.xml fayliga quyidagi bog'liqlikni qo'shaman:
<dependency>
     <groupId>mysql</groupId>
     <artifactId>mysql-connector-java</artifactId>
     <version>5.1.34</version>
</dependency>
application.properties konfiguratsiyasi hozirda quyidagicha:
spring.datasource.url=jdbc:mysql://localhost:3306/springsectut?createDatabaseIfNotExist=true&useSSL=false&autoReconnect=true&useLegacyDatetimeCode=false&serverTimezone=UTC&useUnicode=yes&characterEncoding=UTF-8
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=yourUsername
spring.datasource.password=yourPassword

spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=update

spring.jpa.properties.connection.characterEncoding=utf-8
spring.jpa.properties.connection.CharSet=utf-8
spring.jpa.properties.connection.useUnicode=true

spring.mustache.expose-request-attributes=true

Ob'ektlar va ilovalar mantig'ini yaratish

Ob'ektlar

entitiesKeling , ma'lumotlar bazasi ob'ektlarini joylashtiradigan paket yarataylik . Foydalanuvchi Spring Security konfiguratsiyasi uchun zarur bo'lgan Userinterfeysni amalga oshiradigan sinf tomonidan tavsiflanadi . UserDetailsFoydalanuvchi identifikatori, foydalanuvchi nomi (bu elektron pochta), parol, ism, rol, faoliyat bayrog'i, Google hisobi nomi va elektron pochta manziliga ega bo'ladi ( googleNameva googleUsername).
@Entity
@Table(name = "user")
public class User implements UserDetails
{
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;

  private String username;
  private String password;
  private String name;
  private boolean active;
  private String googleName;
  private String googleUsername;

  @ElementCollection(targetClass = Role.class, fetch = FetchType.EAGER)
  @CollectionTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id"))
  @Enumerated(EnumType.STRING)
  private Set<Role> roles;

    //Геттеры, сеттеры, toString(), equals(), hashcode(), имплементация UserDetails
}
Foydalanuvchi rollari Spring Security-ga kirishni tartibga solish uchun ishlatiladi. Bizning ilovamiz faqat bitta roldan foydalanadi:
public enum Role implements GrantedAuthority
{
  USER;

  @Override
  public String getAuthority()
  {
     return name();
  }
}
Keling, id, eslatma sarlavhasi, eslatma tanasi va u tegishli foydalanuvchi identifikatori bilan eslatma sinfini yarataylik:
@Entity
@Table(name = "note")
public class Note
{
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;

  private String title;
  private String note;
  private Long userId;

    //Геттеры, сеттеры, toString(), equals(), hashcode()
}

Repozitariylar

Ob'ektlarni ma'lumotlar bazasiga saqlash uchun biz uchun barcha iflos ishlarni bajaradigan omborlar kerak. Keling, paketni yaratamiz , unda biz interfeysdan meros bo'lib qolgan reposinterfeyslarni yaratamiz . UserRepoNoteRepoJpaRepository<Entity, Id>
@Service
@Repository
public interface UserRepo extends JpaRepository<User, Long>
{}

@Service
@Repository
public interface NoteRepo extends JpaRepository<Note, Long>
{
  List<Note> findByUserId(Long userId);
}

Kontrollerlar

Bizning eslatmalar xizmatimiz quyidagi sahifalarga ega bo'ladi:
  • Uy;
  • Ro'yxatdan o'tish;
  • Kirish;
  • Foydalanuvchi qaydlari ro'yxati.
Eslatmalar ro'yxatiga faqat vakolatli foydalanuvchi kirish huquqiga ega bo'lishi kerak. Qolgan sahifalar ommaviydir. Keling , asosiy sahifaning odatiy xaritasini o'z ichiga olgan controllerssinfni o'z ichiga olgan paketni yarataylik . IndexControllerSinf RegistrationControllerfoydalanuvchini ro'yxatdan o'tkazish uchun javobgardir. Post-mapping shakldan ma'lumotlarni oladi, foydalanuvchini ma'lumotlar bazasiga saqlaydi va kirish sahifasiga yo'naltiradi. PasswordEncoderkeyinroq bayon qilinadi. U parollarni shifrlash uchun ishlatiladi.
@Controller
public class RegistrationController
{
  @Autowired
  private UserRepo userRepo;

  @Autowired
  private PasswordEncoder passwordEncoder;

  @GetMapping("/registration")
  public String registration()
  {
     return "registration";
  }

  @PostMapping("/registration")
  public String addUser(String name, String username, String password)
  {
     User user = new User();
     user.setName(name);
     user.setUsername(username);
     user.setPassword(passwordEncoder.encode(password));
     user.setActive(true);
     user.setRoles(Collections.singleton(Role.USER));

     userRepo.save(user);

     return "redirect:/login";
  }
Eslatmalar ro'yxati sahifasi uchun mas'ul boshqaruvchida hozirda soddalashtirilgan funksiyalar mavjud bo'lib, ular Spring Security joriy etilgandan keyin yanada murakkablashadi.
@Controller
public class NoteController
{
  @Autowired
  private NoteRepo noteRepo;

  @GetMapping("/notes")
  public String notes(Model model)
  {
     List<Note> notes = noteRepo.findAll();
     model.addAttribute("notes", notes);

     return "notes";
  }

  @PostMapping("/addnote")
  public String addNote(String title, String note)
  {
     Note newNote = new Note();
     newNote.setTitle(title);
     newNote.setNote(note);

     noteRepo.save(newNote);

     return "redirect:/notes";
  }
}
Biz kirish sahifasi uchun kontroller yozmaymiz, chunki u Spring Security tomonidan qo'llaniladi. Buning o'rniga bizga maxsus konfiguratsiya kerak bo'ladi. Odatdagidek, keling, boshqa paket yaratamiz, uni chaqiramiz configva sinfni o'sha yerga joylashtiramiz MvcConfig. Spring Security konfiguratsiyasini yozganimizda, biz "/login" dan foydalanganda qaysi sahifaga murojaat qilayotganimizni bilib oladi.
@Configuration
public class MvcConfig implements WebMvcConfigurer
{
  public void addViewControllers(ViewControllerRegistry registry)
  {
     registry.addViewController("/login").setViewName("login");
     registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
  }
}

Sahifalar

Sahifalar yaratish uchun Mo'ylov shablon mexanizmidan foydalanaman . Siz boshqasini amalga oshirishingiz mumkin, bu muhim emas. Barcha sahifalarda ishlatiladigan meta-ma'lumot uchun meta.mo'ylov fayli yaratilgan. Loyihamiz sahifalarini yanada chiroyli qilish uchun unga Bootstrap ham kiradi. Sahifalar "src/main/resources/templates" katalogida yaratiladi. Fayllarda kengaytmali mo'ylov mavjud. HTML kodini to'g'ridan-to'g'ri maqolaga joylashtirish uni juda katta qiladi, shuning uchun bu erda loyihaning GitHub omboridagi andozalar jildiga havola .

Klassik kirish uchun bahor xavfsizligini sozlash

Spring Security ilova va uning resurslarini ruxsatsiz kirishdan himoya qilishga yordam beradi. SecurityConfigBiz meros qilib olingan sinfda qisqacha ishlaydigan konfiguratsiyani yaratamiz WebSecurityConfigurerAdapter, uni paketga joylashtiramiz config. Keling, uni Spring Security qo'llab-quvvatlashini ta'minlaydigan @EnableWebSecurity izohi va ushbu sinfda ba'zi konfiguratsiyalar mavjudligini ko'rsatadigan @Configuration izohi bilan belgilaymiz. Eslatma: Avtomatik sozlangan pom.xml 2.1.4.RELEASE Spring Boot asosiy komponentining versiyasini o'z ichiga olgan bo'lib, bu xavfsizlikning belgilangan tarzda amalga oshirilishiga to'sqinlik qildi. Loyihada ziddiyatlarni oldini olish uchun versiyani 2.0.1.RELEASE ga o'zgartirish tavsiya etiladi.

SecurityConfig asosiy konfiguratsiyasi

Bizning konfiguratsiyamiz quyidagilarni amalga oshirishi mumkin:
  1. Parollarni shifrlash BCryptPasswordEncoder:

    @Autowired
    private PasswordEncoder passwordEncoder;
    
    @Bean
    PasswordEncoder passwordEncoder()
    {
      PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
      return passwordEncoder;
    }
  2. Maxsus yozilgan autentifikatsiya provayderi yordamida tizimga kiring:

    @Autowired
    private AuthProvider authProvider;
    
    @Override
    protected void configure(AuthenticationManagerBuilder auth)
    {
      auth.authenticationProvider(authProvider);
    }
  3. Anonim foydalanuvchilarga bosh sahifaga, ro'yxatdan o'tish va kirish sahifalariga kirishga ruxsat bering. Boshqa barcha so'rovlar tizimga kirgan foydalanuvchilar tomonidan bajarilishi kerak. Kirish sahifasi sifatida avval tavsiflangan “/login” ni belgilaymiz. Agar tizimga kirish muvaffaqiyatli bo'lsa, foydalanuvchi qaydlar ro'yxati bilan sahifaga o'tadi, agar xato bo'lsa, foydalanuvchi kirish sahifasida qoladi. Muvaffaqiyatli chiqqandan so'ng, foydalanuvchi asosiy sahifaga o'tadi.

    @Override
    protected void configure(HttpSecurity http) throws Exception
    {
      http
            .authorizeRequests()
            .antMatchers("/resources/**", "/", "/login**", "/registration").permitAll()
            .anyRequest().authenticated()
            .and().formLogin().loginPage("/login")
            .defaultSuccessUrl("/notes").failureUrl("/login?error").permitAll()
            .and().logout().logoutSuccessUrl("/").permitAll();
    }

Shaxsiy foydalanuvchi login

O'z-o'zidan yozilgan AuthProviderfoydalanuvchiga nafaqat elektron pochta orqali, balki foydalanuvchi nomi bilan ham kirish imkonini beradi.
@Component
public class AuthProvider implements AuthenticationProvider
{
  @Autowired
  private UserService userService;

  @Autowired
  private PasswordEncoder passwordEncoder;

  public Authentication authenticate(Authentication authentication) throws AuthenticationException
  {
     String username = authentication.getName();
     String password = (String) authentication.getCredentials();

     User user = (User) userService.loadUserByUsername(username);

     if(user != null && (user.getUsername().equals(username) || user.getName().equals(username)))
     {
        if(!passwordEncoder.matches(password, user.getPassword()))
        {
           throw new BadCredentialsException("Wrong password");
        }

        Collection<? extends GrantedAuthority> authorities = user.getAuthorities();

        return new UsernamePasswordAuthenticationToken(user, password, authorities);
     }
     else
        throw new BadCredentialsException("Username not found");
  }

  public boolean supports(Class<?> arg)
  {
     return true;
  }
}
Siz sezganingizdek, UserServicepaketda joylashgan sinf foydalanuvchini yuklash uchun javobgardir services. Bizning holatda, u foydalanuvchini nafaqat maydon username, masalan, o'rnatilgan dastur, balki foydalanuvchi nomi, Google hisobi nomi va Google hisobi elektron pochtasi bo'yicha ham qidiradi. OAuth2 orqali kirishni amalga oshirishda oxirgi ikki usul biz uchun foydali bo'ladi. Bu erda sinf qisqartirilgan versiyada berilgan.
@Service
public class UserService implements UserDetailsService
{
  @Autowired
  private UserRepo userRepo;

  @Override
  public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
  {
     User userFindByUsername = userRepo.findByUsername(username);
     //Остальные поиски

     if(userFindByUsername != null)
     {
        return userFindByUsername;
     }
     //Остальные проверки
     return null;
  }
}
Eslatma: kerakli usullarni yozishni unutmang UserRepo!

Keling, boshqaruvchini yaxshilaymiz

Biz Spring Security-ni sozladik. Endi qaydlar boshqaruvchisida bundan foydalanish vaqti keldi. Endi har bir xaritalash qo'shimcha Principal parametrini qabul qiladi va u orqali foydalanuvchini topishga harakat qiladi. Nega men sinfni to'g'ridan-to'g'ri kirita olmayman User? Keyin ijtimoiy tarmoqlar orqali login yozganimizda foydalanuvchilar turlarining mos kelmasligi sababli ziddiyat yuzaga keladi. Biz oldindan kerakli moslashuvchanlikni ta'minlaymiz. Endi bizning qaydlar boshqaruvchisi kodi quyidagicha ko'rinadi:
@GetMapping("/notes")
public String notes(Principal principal, Model model)
{
  User user = (User) userService.loadUserByUsername(principal.getName());
  List<Note> notes = noteRepo.findByUserId(user.getId());
  model.addAttribute("notes", notes);
  model.addAttribute("user", user);

  return "notes";
}

@PostMapping("/addnote")
public String addNote(Principal principal, String title, String note)
{
  User user = (User) userService.loadUserByUsername(principal.getName());

  Note newNote = new Note();
  newNote.setTitle(title);
  newNote.setNote(note);
  newNote.setUserId(user.getId());

  noteRepo.save(newNote);

  return "redirect:/notes";
}
Eslatma: loyihada sukut bo'yicha CSRF himoyasi yoqilgan , shuning uchun uni o'zingiz uchun o'chirib qo'ying (http.csrf().disable()) yoki maqola muallifi sifatida csrf tokeni bilan yashirin maydon qo'shishni unutmang. barcha post so'rovlariga.

Ishga tushirish

Loyihani ishga tushirishga harakat qilyapmiz.
Notes xizmati misolidan foydalanib, elektron pochta va OAuth2 orqali Spring Security-ga muntazam kirishni joriy qilaylik - 1
Eslatmalar xizmati misolidan foydalanib, elektron pochta va OAuth2 orqali Spring Security-ga muntazam kirishni joriy qilaylik - 2
Ma'lumotlar bazasida yangi foydalanuvchi paydo bo'lganini ko'ramiz. Parol shifrlangan.
Eslatmalar xizmati misolidan foydalanib, elektron pochta va OAuth2 orqali Spring Security-ga muntazam kirishni joriy qilaylik - 3
Notes xizmati misolidan foydalanib, elektron pochta va OAuth2 orqali Spring Security-ga muntazam kirishni joriy qilaylik - 4
Eslatmalar xizmati misolidan foydalanib, elektron pochta va OAuth2 orqali Spring Security-ga muntazam kirishni joriy qilaylik - 5
Eslatmalar xizmati misolidan foydalanib, elektron pochta va OAuth2 orqali Spring Security-ga muntazam kirishni joriy qilaylik - 6
Eslatmalar ma'lumotlar bazasida saqlanadi.
Notes xizmati misolidan foydalanib, elektron pochta va OAuth2 orqali Spring Security-ga muntazam kirishni joriy qilaylik - 7
Loyiha muvaffaqiyatli boshlanganini va ishlayotganini ko'ramiz. To'liq baxt uchun bizga faqat ijtimoiy tarmoqlar orqali kirish imkoniyati kerak. Xo'sh, boshlaylik!

Spring Security-da Google-dan foydalanib, OAuth2-ni o'rnatish

OAuth2 ni amalga oshirishda men Spring dan ushbu rasmiy qo'llanmaga tayandim . OAuth2-ni qo'llab-quvvatlash uchun pom.xml-ga quyidagi kutubxonani qo'shing:
<dependency>
  <groupId>org.springframework.security.oauth.boot</groupId>
  <artifactId>spring-security-oauth2-autoconfigure</artifactId>
  <version>2.0.0.RELEASE</version>
</dependency>
Keling, Spring Security konfiguratsiyasini o'zgartiraylik SecurityConfig. Birinchidan, @EnableOAuth2Client izohini qo'shamiz. Ijtimoiy tarmoqlar orqali tizimga kirishingiz kerak bo'lgan narsalarni avtomatik ravishda tortib oladi.

Filtr konfiguratsiyasi va application.properties

Xavfsizlik konfiguratsiyasida foydalanish uchun OAuth2ClientContext ni kiritamiz.
@Autowired
private OAuth2ClientContext oAuth2ClientContext;
OAuth2ClientContext foydalanuvchining ijtimoiy kirish soʻrovini tasdiqlovchi filtr yaratishda foydalaniladi. Filtr @EnableOAuth2Client izohi tufayli mavjud. Biz qilishimiz kerak bo'lgan yagona narsa, asosiy Spring Security filtridan oldin uni to'g'ri tartibda chaqirishdir . Shundan keyingina biz OAuth2 bilan tizimga kirish jarayonida qayta yo'naltirishlarni ushlay olamiz. Buning uchun biz dan foydalanamiz FilterRegistrationBean, unda biz filtrimizning ustuvorligini -100 ga o'rnatamiz.
@Bean
public FilterRegistrationBean oAuth2ClientFilterRegistration(OAuth2ClientContextFilter oAuth2ClientContextFilter)
{
  FilterRegistrationBean registration = new FilterRegistrationBean();
  registration.setFilter(oAuth2ClientContextFilter);
  registration.setOrder(-100);
  return registration;
}

private Filter ssoFilter()
{
  OAuth2ClientAuthenticationProcessingFilter googleFilter = new OAuth2ClientAuthenticationProcessingFilter("/login/google");
  OAuth2RestTemplate googleTemplate = new OAuth2RestTemplate(google(), oAuth2ClientContext);
  googleFilter.setRestTemplate(googleTemplate);
  CustomUserInfoTokenServices tokenServices = new CustomUserInfoTokenServices(googleResource().getUserInfoUri(), google().getClientId());
  tokenServices.setRestTemplate(googleTemplate);
  googleFilter.setTokenServices(tokenServices);
  tokenServices.setUserRepo(userRepo);
  tokenServices.setPasswordEncoder(passwordEncoder);
  return googleFilter;
}
Shuningdek, configure(HttpSecurity http) funksiyasiga yangi filtr qo'shishingiz kerak:
http.addFilterBefore(ssoFilter(), UsernamePasswordAuthenticationFilter.class);
Filtr mijozning Google orqali ro'yxatdan o'tganligini ham bilishi kerak. @ConfigurationProperties izohi application.properties da qaysi konfiguratsiya xususiyatlarini izlash kerakligini belgilaydi.
@Bean
@ConfigurationProperties("google.client")
public AuthorizationCodeResourceDetails google()
{
  return new AuthorizationCodeResourceDetails();
}
Autentifikatsiyani yakunlash uchun Google foydalanuvchi maʼlumotlarining soʻnggi nuqtasini koʻrsatishingiz kerak:
@Bean
@ConfigurationProperties("google.resource")
public ResourceServerProperties googleResource()
{
  return new ResourceServerProperties();
}
Ilovamizni Google Cloud Platform- da ro'yxatdan o'tkazgandan so'ng , biz application.properties ga tegishli prefikslar bilan xususiyatlarni qo'shamiz:
google.client.clientId=yourClientId
google.client.clientSecret=yourClientSecret
google.client.accessTokenUri=https://www.googleapis.com/oauth2/v4/token
google.client.userAuthorizationUri=https://accounts.google.com/o/oauth2/v2/auth
google.client.clientAuthenticationScheme=form
google.client.scope=openid,email,profile
google.resource.userInfoUri=https://www.googleapis.com/oauth2/v3/userinfo
google.resource.preferTokenInfo=true

Ilovani Google Cloud Platform bilan ro'yxatdan o'tkazishning muhim jihatlari

Yoʻl: API va xizmatlar -> Hisob maʼlumotlari OAuth kirish soʻrovi oynasi:
  • Ilova nomi: Bahorgi login formasi va OAuth2 qoʻllanmasi
  • Yordam elektron pochta manzili: sizning elektron pochtangiz
  • Google API uchun qamrov: elektron pochta, profil, openid
  • Vakolatli domenlar: me.org
  • Ilovaning asosiy sahifasiga havola: http://me.org:8080
  • Ilova maxfiylik siyosatiga havola: http://me.org:8080
  • Ilovadan foydalanish shartlariga havola: http://me.org:8080
Hisob maʼlumotlari:
  • Turi: Veb-ilova
  • Sarlavha: Bahorgi tizimga kirish shakli va OAuth2 qo'llanmasi
  • Ruxsat etilgan JavaScript manbalari: http://me.org, http://me.org:8080
  • Ruxsat etilgan qayta yo'naltirish URI'lari: http://me.org:8080/login, http://me.org:8080/login/google
Eslatma: Google localhost:8080 manzili bilan ishlashni istamaganligi sababli, oxirida "127.0.0.1 me.org" qatorini yoki C:\Windows\System32\drivers\etc\hosts fayliga o'xshash narsani qo'shing. Asosiysi, domen klassik shaklda.

CustomUserInfoTokenServices

Filtr funksiyasi tavsifida Custom so'zini payqadingizmi? Sinf CustomUserInfoTokenServices. Ha, biz blackjack va foydalanuvchini ma'lumotlar bazasida saqlash qobiliyati bilan o'z sinfimizni yaratamiz! IntelliJ IDEA-da Ctrl-N klaviatura yorlig'idan foydalanib, siz UserInfoTokenServicessukut bo'yicha qanday amalga oshirilishini topishingiz va ko'rishingiz mumkin. Keling, uning kodini yangi yaratilgan sinfga ko'chiraylik CustomUserInfoTokenServices. Uning ko'p qismini o'zgarishsiz qoldirish mumkin. Funktsiyalar mantig'ini o'zgartirishdan oldin sinfning shaxsiy maydonlari UserReposifatida qo'shamiz PasswordEncoder. Keling, ular uchun sozlagichlarni yarataylik. SecurityConfig sinfiga @Autowired UserRepo userRepo qo'shamiz. Filtrni yaratish usulidagi xatoga ko'rsatgich qanday yo'qolganiga qaraymiz va biz quvonamiz. Nima uchun @Autowired to'g'ridan-to'g'ri CustomUserInfoTokenServices xizmatiga qo'llanilmadi? Chunki bu sinf bog'liqlikni tanlamaydi, chunki uning o'zi hech qanday Spring izohi bilan belgilanmagan va filtr e'lon qilinganda uning konstruktori aniq yaratilgan. Shunga ko'ra, Springning DI mexanizmi bu haqda bilmaydi. Agar biz ushbu sinfdagi biror narsaga @Autowired izohini qo'shsak, biz foydalanilganda NullPointerExceptionni olamiz. Ammo aniq sozlagichlar orqali hamma narsa juda yaxshi ishlaydi. Kerakli komponentlarni amalga oshirgandan so'ng, asosiy qiziqish ob'ekti foydalanuvchi haqidagi ma'lumotlarga ega Map<String, Object> olinadigan loadAuthentication funksiyasiga aylanadi. Aynan shu loyihada men ijtimoiy tarmoq orqali kirgan foydalanuvchini ma'lumotlar bazasiga saqlashni amalga oshirdim. Biz Google hisobidan OAuth2 provayderi sifatida foydalanayotganimiz sababli, xaritada Google uchun odatiy bo‘lgan “sub” maydoni mavjudligini tekshiramiz. Agar u mavjud bo'lsa, bu foydalanuvchi haqidagi ma'lumot to'g'ri qabul qilinganligini anglatadi. Biz yangi foydalanuvchi yaratamiz va uni ma'lumotlar bazasiga saqlaymiz.
@Override
public OAuth2Authentication loadAuthentication(String accessToken)
     throws AuthenticationException, InvalidTokenException
{
  Map<String, Object> map = getMap(this.userInfoEndpointUrl, accessToken);

  if(map.containsKey("sub"))
  {
     String googleName = (String) map.get("name");
     String googleUsername = (String) map.get("email");

     User user = userRepo.findByGoogleUsername(googleUsername);

     if(user == null)
     {
        user = new User();
        user.setActive(true);
        user.setRoles(Collections.singleton(Role.USER));
     }

     user.setName(googleName);
     user.setUsername(googleUsername);
     user.setGoogleName(googleName);
     user.setGoogleUsername(googleUsername);
     user.setPassword(passwordEncoder.encode("oauth2user"));

     userRepo.save(user);
  }

  if (map.containsKey("error"))
  {
     this.logger.debug("userinfo returned error: " + map.get("error"));
     throw new InvalidTokenException(accessToken);
  }
  return extractAuthentication(map);
}
Bir nechta provayderlardan foydalanganda siz bitta CustomUserInfoTokenServices-da turli xil variantlarni belgilashingiz va filtr deklaratsiyasi usulida o'xshash xizmatlarning turli sinflarini ro'yxatdan o'tkazishingiz mumkin. Endi foydalanuvchi ham, OAuth2Authentication ham asosiy vazifani bajarishi mumkin. Biz UserService-da foydalanuvchining Google ma'lumotlari orqali yuklanishini oldindan hisobga olganimiz sababli, dastur ikkala turdagi foydalanuvchilar uchun ham ishlaydi. Biz loyihaning asosiy sahifa boshqaruvchisini OAuth2 yordamida tizimga kirgan foydalanuvchilarni qaydlar sahifasiga yoʻnaltirish uchun oʻzgartiramiz.
@GetMapping("/")
public String index(Principal principal)
{
  if(principal != null)
  {
     return "redirect:/notes";
  }
  return "index";
}

Loyihaning yakuniy boshlanishi

Kichkina kosmetik o'zgarishlar va chiqish tugmachasini qo'shgandan so'ng, biz loyihani yakuniy ishga tushiramiz.
Eslatmalar xizmati misolidan foydalanib, elektron pochta va OAuth2 orqali Spring Security-ga muntazam kirishni joriy qilaylik - 8
Eslatmalar xizmati misolidan foydalanib, elektron pochta va OAuth2 orqali Spring Security-ga muntazam kirishni joriy qilaylik - 9
Eslatmalar xizmati misolidan foydalanib, elektron pochta va OAuth2 orqali Spring Security-ga muntazam kirishni joriy qilaylik - 10
Eslatmalar xizmati misolidan foydalanib, elektron pochta va OAuth2 orqali Spring Security-ga muntazam kirishni joriy qilaylik - 11
Eslatmalar xizmati misolidan foydalanib, elektron pochta va OAuth2 orqali Spring Security-ga muntazam kirishni joriy qilaylik - 12
Eslatmalar xizmati misolidan foydalanib, elektron pochta va OAuth2 orqali Spring Security-ga muntazam kirishni joriy qilaylik - 13
Eslatmalar xizmati misolidan foydalanib, elektron pochta va OAuth2 orqali Spring Security-ga muntazam kirishni joriy qilaylik - 14
Notes xizmati misolidan foydalanib, elektron pochta va OAuth2 orqali Spring Security-ga muntazam kirishni joriy qilaylik - 15
Foydalanuvchi oddiy shakl orqali ham, Google hisobi orqali ham muvaffaqiyatli tizimga kiradi. Bu biz xohlagan narsa edi! Umid qilamanki, ushbu maqola veb-ilovani yaratish, uni Spring Security bilan himoya qilish va turli xil kirish usullarini birlashtirish bo'yicha ba'zi fikrlarni aniqladi. To'liq loyiha kodi bilan mumkin
Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION