JavaRush /Blog Java /Random-VI /Hãy giới thiệu tính năng đăng nhập thông thường qua email...

Hãy giới thiệu tính năng đăng nhập thông thường qua email và OAuth2 cho Spring Security bằng ví dụ về dịch vụ ghi chú

Xuất bản trong nhóm
Trong khi viết đơn đăng ký, tôi gặp phải tình trạng thiếu bài viết rõ ràng về cách thu hút người dùng đăng ký cả qua email và mạng xã hội. Có những hướng dẫn hay về cách thiết lập biểu mẫu đăng nhập cổ điển. Đã có những hướng dẫn hay về OAuth2 . Có rất ít thông tin về cách kết hợp hai phương pháp. Trong quá trình tìm kiếm, chúng tôi đã có thể đưa ra một giải pháp khả thi. Nó không tự cho mình là chân lý tối thượng, nhưng nó hoàn thành chức năng của mình. Trong bài viết này, tôi sẽ hướng dẫn cách triển khai dịch vụ lưu trữ ghi chú với cấu hình Spring Security tương tự từ đầu. Hãy giới thiệu tính năng đăng nhập thông thường qua email và OAuth2 vào Spring Security bằng ví dụ về dịch vụ ghi chú - 1Lưu ý: sẽ rất tốt nếu người đọc đã xem qua ít nhất một vài hướng dẫn về Spring, vì sự chú ý sẽ chỉ tập trung vào Spring Security mà không có giải thích chi tiết về kho lưu trữ, bộ điều khiển, v.v. Nếu không, một bài viết vốn đã khá dài sẽ trở thành trở nên khổng lồ. Nội dung
  1. Tạo một dự án
  2. Tạo các thực thể và logic ứng dụng
    1. Thực thể
    2. Kho lưu trữ
    3. Bộ điều khiển
    4. Trang
  3. Định cấu hình bảo mật mùa xuân cho đăng nhập cổ điển
    1. Cấu hình cơ bản SecurityConfig
    2. Đăng nhập người dùng tùy chỉnh
    3. Hãy cải thiện bộ điều khiển
    4. Phóng
  4. Thiết lập OAuth2 bằng Google làm ví dụ trong Spring Security
    1. Cấu hình bộ lọc và application.properties
    2. Điểm nổi bật của việc đăng ký ứng dụng với Google Cloud Platform
    3. CustomUserInfoTokenServices
  5. Lễ ra mắt cuối cùng của dự án

Tạo một dự án

Chúng tôi truy cập start.spring.io và hình thành nền tảng của dự án:
  • Web - khởi chạy một ứng dụng trên Tomcat tích hợp sẵn, ánh xạ url và những thứ tương tự;
  • JPA - kết nối cơ sở dữ liệu;
  • Mustache là một công cụ tạo mẫu được sử dụng để tạo các trang web;
  • Bảo mật - bảo vệ ứng dụng. Đây là mục đích của bài viết này.
Tải xuống kho lưu trữ kết quả và giải nén nó vào thư mục bạn cần. Chúng tôi khởi chạy nó trong IDE. Bạn có thể chọn cơ sở dữ liệu theo ý mình. Tôi sử dụng MySQL làm cơ sở dữ liệu cho dự án, vì vậy tôi thêm phần phụ thuộc sau vào tệp pom.xml trong khối <dependency>:
<dependency>
     <groupId>mysql</groupId>
     <artifactId>mysql-connector-java</artifactId>
     <version>5.1.34</version>
</dependency>
Cấu hình application.properties hiện tại như sau:
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

Tạo các thực thể và logic ứng dụng

Thực thể

Hãy tạo một gói entitiestrong đó chúng ta sẽ đặt các thực thể cơ sở dữ liệu. Người dùng sẽ được mô tả bởi một lớp Userthực hiện giao diện UserDetails, lớp này sẽ cần thiết cho cấu hình Spring Security. Người dùng sẽ có id, tên người dùng (đây là email), mật khẩu, tên, vai trò, cờ hoạt động, tên tài khoản Google và email ( googleNamegoogleUsername).
@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
}
Vai trò của người dùng được sử dụng để điều chỉnh quyền truy cập trong Spring Security. Ứng dụng của chúng tôi sẽ chỉ sử dụng một vai trò:
public enum Role implements GrantedAuthority
{
  USER;

  @Override
  public String getAuthority()
  {
     return name();
  }
}
Hãy tạo một lớp ghi chú với id, tiêu đề ghi chú, nội dung ghi chú và id của người dùng mà nó thuộc về:
@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()
}

Kho lưu trữ

Để lưu các thực thể vào cơ sở dữ liệu, chúng ta cần các kho lưu trữ có thể thực hiện tất cả công việc bẩn thỉu cho chúng ta. Hãy tạo một gói repos, trong đó chúng ta sẽ tạo các giao diện UserRepođược kế thừa NoteRepotừ giao diện đó JpaRepository<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);
}

Bộ điều khiển

Dịch vụ ghi chú của chúng tôi sẽ có các trang sau:
  • Trang chủ;
  • Sự đăng ký;
  • Cổng vào;
  • Danh sách ghi chú của người dùng.
Chỉ người dùng được ủy quyền mới có quyền truy cập vào danh sách ghi chú. Các trang còn lại là công khai. Hãy tạo một gói controllerschứa một lớp IndexControllerchứa ánh xạ tải thông thường của trang chính. Lớp RegistrationControllercó trách nhiệm đăng ký người dùng. Ánh xạ sau lấy dữ liệu từ biểu mẫu, lưu người dùng vào cơ sở dữ liệu và chuyển hướng đến trang đăng nhập. PasswordEncodersẽ được mô tả sau. Nó được sử dụng để mã hóa mật khẩu.
@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";
  }
Bộ điều khiển chịu trách nhiệm về trang danh sách ghi chú hiện có chức năng đơn giản hóa, chức năng này sẽ trở nên phức tạp hơn sau khi triển khai Spring Security.
@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";
  }
}
Chúng tôi sẽ không viết bộ điều khiển cho trang đăng nhập vì nó được sử dụng trong Spring Security. Thay vào đó, chúng ta sẽ cần một cấu hình đặc biệt. Như thường lệ, hãy tạo một gói khác, gọi nó là config, và đặt lớp vào đó MvcConfig. Khi chúng ta viết cấu hình Spring Security, nó sẽ biết chúng ta đang đề cập đến trang nào khi sử dụng "/login".
@Configuration
public class MvcConfig implements WebMvcConfigurer
{
  public void addViewControllers(ViewControllerRegistry registry)
  {
     registry.addViewController("/login").setViewName("login");
     registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
  }
}

Trang

Tôi sử dụng công cụ tạo mẫu Mustache để tạo trang . Bạn có thể thực hiện một cái khác, điều đó không thành vấn đề. Tệp meta.mustache đã được tạo cho thông tin meta được sử dụng trên tất cả các trang. Nó cũng bao gồm Bootstrap để làm cho các trang trong dự án của chúng tôi trông đẹp hơn. Các trang được tạo trong thư mục "src/main/resources/templates". Các tập tin có phần mở rộng ria mép. Việc đặt mã html trực tiếp vào bài viết sẽ khiến nó quá lớn, vì vậy đây là liên kết đến thư mục mẫu trong kho GitHub của dự án .

Định cấu hình bảo mật mùa xuân cho đăng nhập cổ điển

Spring Security giúp chúng tôi bảo vệ ứng dụng và tài nguyên của nó khỏi bị truy cập trái phép. Chúng ta sẽ tạo một cấu hình làm việc ngắn gọn trong một lớp SecurityConfigđược kế thừa từ WebSecurityConfigurerAdapter, mà chúng ta sẽ đặt trong gói config. Hãy đánh dấu nó bằng chú thích @EnableWebSecurity, chú thích này sẽ kích hoạt hỗ trợ Spring Security và chú thích @Configuration, cho biết rằng lớp này có chứa một số cấu hình. Lưu ý: phiên bản chứa pom.xml được cấu hình tự động của thành phần cha mẹ Spring Boot 2.1.4.RELEASE, phiên bản này đã ngăn cản việc triển khai Bảo mật theo cách đã thiết lập. Để tránh xung đột trong dự án, nên thay đổi phiên bản thành 2.0.1.RELEASE.

Cấu hình cơ bản SecurityConfig

Cấu hình của chúng tôi sẽ có thể:
  1. Mã hóa mật khẩu bằng cách sử dụng BCryptPasswordEncoder:

    @Autowired
    private PasswordEncoder passwordEncoder;
    
    @Bean
    PasswordEncoder passwordEncoder()
    {
      PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
      return passwordEncoder;
    }
  2. Đăng nhập bằng cách sử dụng nhà cung cấp xác thực bằng văn bản đặc biệt:

    @Autowired
    private AuthProvider authProvider;
    
    @Override
    protected void configure(AuthenticationManagerBuilder auth)
    {
      auth.authenticationProvider(authProvider);
    }
  3. Cho phép người dùng ẩn danh truy cập vào trang chủ, trang đăng ký và đăng nhập. Tất cả các yêu cầu khác phải được thực hiện bởi người dùng đã đăng nhập. Hãy chỉ định “/đăng nhập” được mô tả trước đó làm trang đăng nhập. Nếu đăng nhập thành công, người dùng sẽ được đưa đến trang có danh sách ghi chú, nếu có sai sót, người dùng sẽ ở lại trang đăng nhập. Sau khi thoát thành công, người dùng sẽ được đưa đến trang chính.

    @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();
    }

Đăng nhập người dùng tùy chỉnh

Một cái tự viết AuthProvidersẽ cho phép người dùng đăng nhập không chỉ bằng email mà còn bằng tên người dùng.
@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;
  }
}
Như bạn có thể nhận thấy, lớp UserServicenằm trong gói chịu trách nhiệm tải các tệp services. Trong trường hợp của chúng tôi, nó tìm kiếm người dùng không chỉ theo trường username, như triển khai tích hợp, mà còn theo tên người dùng, tên tài khoản Google và email tài khoản Google. Hai phương pháp cuối cùng sẽ hữu ích cho chúng ta khi triển khai đăng nhập qua OAuth2. Ở đây lớp học được đưa ra trong một phiên bản viết tắt.
@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;
  }
}
Lưu ý: đừng quên viết các phương thức cần thiết vào UserRepo!

Hãy cải thiện bộ điều khiển

Chúng tôi đã cấu hình Spring Security. Bây giờ là lúc tận dụng lợi thế này trong bộ điều khiển ghi chú của bạn. Bây giờ, mỗi ánh xạ sẽ chấp nhận một tham số Chính bổ sung, theo đó nó sẽ cố gắng tìm người dùng. Tại sao tôi không thể tiêm trực tiếp vào lớp học User? Khi đó sẽ xảy ra xung đột do không phù hợp về loại người dùng khi chúng ta viết thông tin đăng nhập qua mạng xã hội. Chúng tôi cung cấp trước sự linh hoạt cần thiết. Mã điều khiển ghi chú của chúng tôi bây giờ trông như thế này:
@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";
}
Lưu ý: dự án đã bật tính năng bảo vệ CSRF theo mặc định , do đó, hãy tự tắt tính năng này (http.csrf().disable()) hoặc đừng quên, với tư cách là tác giả của bài viết, thêm trường ẩn bằng mã thông báo csrf cho tất cả các yêu cầu đăng bài.

Phóng

Chúng tôi đang cố gắng khởi động dự án.
Hãy giới thiệu tính năng đăng nhập thông thường qua email và OAuth2 vào Spring Security bằng ví dụ về dịch vụ ghi chú - 1
Hãy giới thiệu tính năng đăng nhập thông thường qua email và OAuth2 vào Spring Security bằng ví dụ về dịch vụ ghi chú - 2
Chúng tôi thấy rằng một người dùng mới đã xuất hiện trong cơ sở dữ liệu. Mật khẩu được mã hóa.
Hãy giới thiệu tính năng đăng nhập thông thường qua email và OAuth2 vào Spring Security bằng ví dụ về dịch vụ ghi chú - 3
Hãy giới thiệu tính năng đăng nhập thông thường qua email và OAuth2 vào Spring Security bằng ví dụ về dịch vụ ghi chú - 4
Hãy giới thiệu tính năng đăng nhập thông thường qua email và OAuth2 vào Spring Security bằng ví dụ về dịch vụ ghi chú - 5
Hãy giới thiệu tính năng đăng nhập thông thường qua email và OAuth2 vào Spring Security bằng ví dụ về dịch vụ ghi chú - 6
Các ghi chú được lưu vào cơ sở dữ liệu.
Hãy giới thiệu tính năng đăng nhập thông thường qua email và OAuth2 vào Spring Security bằng ví dụ về dịch vụ ghi chú - 7
Chúng tôi thấy rằng dự án đã được khởi chạy và chạy thành công. Để có được hạnh phúc trọn vẹn, chúng ta chỉ cần khả năng đăng nhập thông qua mạng xã hội. Vâng, hãy bắt đầu!

Thiết lập OAuth2 bằng Google làm ví dụ trong Spring Security

Khi triển khai OAuth2, tôi đã dựa vào hướng dẫn chính thức này từ Spring . Để hỗ trợ OAuth2, hãy thêm thư viện sau vào pom.xml:
<dependency>
  <groupId>org.springframework.security.oauth.boot</groupId>
  <artifactId>spring-security-oauth2-autoconfigure</artifactId>
  <version>2.0.0.RELEASE</version>
</dependency>
Hãy sửa đổi cấu hình Spring Security của chúng tôi trong tệp SecurityConfig. Đầu tiên, hãy thêm chú thích @EnableOAuth2Client. Nó sẽ tự động hiện lên những gì bạn cần để đăng nhập qua mạng xã hội.

Cấu hình bộ lọc và application.properties

Hãy đưa OAuth2ClientContext vào để sử dụng trong cấu hình bảo mật của chúng tôi.
@Autowired
private OAuth2ClientContext oAuth2ClientContext;
OAuth2ClientContext được sử dụng khi tạo bộ lọc xác thực yêu cầu đăng nhập mạng xã hội của người dùng. Bộ lọc khả dụng nhờ chú thích @EnableOAuth2Client. Tất cả những gì chúng ta cần làm là gọi nó theo đúng thứ tự, trước bộ lọc Spring Security chính. Chỉ khi đó chúng tôi mới có thể nắm bắt được các chuyển hướng trong quá trình đăng nhập bằng OAuth2. Để thực hiện việc này, chúng tôi sử dụng FilterRegistrationBean, trong đó chúng tôi đặt mức độ ưu tiên của bộ lọc thành -100.
@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;
}
Bạn cũng cần thêm bộ lọc mới vào hàm configure(HttpSecurity http):
http.addFilterBefore(ssoFilter(), UsernamePasswordAuthenticationFilter.class);
Bộ lọc cũng cần biết rằng khách hàng đã đăng ký qua Google. Chú thích @ConfigurationProperties chỉ định các thuộc tính cấu hình cần tìm trong application.properties.
@Bean
@ConfigurationProperties("google.client")
public AuthorizationCodeResourceDetails google()
{
  return new AuthorizationCodeResourceDetails();
}
Để hoàn tất xác thực, bạn cần chỉ định điểm cuối thông tin người dùng Google:
@Bean
@ConfigurationProperties("google.resource")
public ResourceServerProperties googleResource()
{
  return new ResourceServerProperties();
}
Sau khi đăng ký ứng dụng của chúng tôi trong Google Cloud Platform , chúng tôi sẽ thêm các thuộc tính có tiền tố thích hợp vào application.properties:
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

Điểm nổi bật của việc đăng ký ứng dụng với Google Cloud Platform

Đường dẫn: API và Dịch vụ -> Cửa sổ yêu cầu quyền truy cập OAuth thông tin xác thực:
  • Tên ứng dụng: Biểu mẫu đăng nhập mùa xuân và hướng dẫn OAuth2
  • Địa chỉ email hỗ trợ: email của bạn
  • Phạm vi API của Google: email, hồ sơ, openid
  • Tên miền được ủy quyền: me.org
  • Link tới trang chính của ứng dụng: http://me.org:8080
  • Liên kết đến chính sách bảo mật của ứng dụng: http://me.org:8080
  • Link điều khoản sử dụng ứng dụng: http://me.org:8080
Thông tin xác thực:
  • Kiểu: Ứng dụng web
  • Tiêu đề: Biểu mẫu đăng nhập mùa xuân và hướng dẫn OAuth2
  • Các nguồn JavaScript được phép: http://me.org, http://me.org:8080
  • URI chuyển hướng được phép: http://me.org:8080/login, http://me.org:8080/login/google
Lưu ý: vì Google không muốn làm việc với địa chỉ localhost:8080, hãy thêm dòng “127.0.0.1 me.org” hoặc dòng nào đó tương tự như tệp C:\Windows\System32\drivers\etc\hosts ở cuối. Điều chính là tên miền ở dạng cổ điển.

CustomUserInfoTokenServices

Bạn có để ý thấy từ Custom trong phần mô tả chức năng lọc không? Lớp học CustomUserInfoTokenServices. Có, chúng tôi sẽ tạo lớp riêng của mình với blackjack và khả năng lưu người dùng vào cơ sở dữ liệu! Sử dụng phím tắt Ctrl-N trong IntelliJ IDEA, bạn có thể tìm và xem cách UserInfoTokenServicestriển khai mặc định. Hãy sao chép mã của nó vào lớp mới được tạo CustomUserInfoTokenServices. Hầu hết nó có thể được giữ nguyên. Trước khi thay đổi logic của các hàm, hãy thêm UserRepoand làm trường riêng của lớp PasswordEncoder. Hãy tạo setters cho họ. Hãy thêm @Autowired UserRepo userRepo vào lớp SecurityConfig. Chúng tôi xem xét cách con trỏ tới lỗi trong phương thức tạo bộ lọc biến mất và chúng tôi rất vui mừng. Tại sao @Autowired không thể được áp dụng trực tiếp cho CustomUserInfoTokenServices? Bởi vì lớp này sẽ không nhận phần phụ thuộc, vì bản thân nó không được đánh dấu bằng bất kỳ chú thích Spring nào và hàm tạo của nó được tạo một cách rõ ràng khi bộ lọc được khai báo. Theo đó, cơ chế DI của Spring không biết về nó. Nếu chúng ta chú thích @Autowired trên bất kỳ thứ gì trong lớp này, chúng ta sẽ nhận được NullPointerException khi sử dụng. Nhưng thông qua setters rõ ràng, mọi thứ đều hoạt động rất tốt. Sau khi triển khai các thành phần cần thiết, đối tượng quan tâm chính sẽ trở thành hàm loadAuthentication, trong đó Map<String, Object> với thông tin về người dùng được truy xuất. Trong dự án này, tôi đã triển khai việc lưu người dùng đã đăng nhập qua mạng xã hội vào cơ sở dữ liệu. Vì chúng tôi đang sử dụng tài khoản Google làm nhà cung cấp OAuth2 nên chúng tôi sẽ kiểm tra xem bản đồ có chứa trường “phụ” điển hình cho Google hay không. Nếu nó hiện diện, điều đó có nghĩa là thông tin về người dùng đã được nhận chính xác. Chúng tôi tạo một người dùng mới và lưu nó vào cơ sở dữ liệu.
@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);
}
Khi sử dụng một số nhà cung cấp, bạn có thể chỉ định các tùy chọn khác nhau trong một CustomUserInfoTokenServices và đăng ký các lớp dịch vụ tương tự khác nhau trong phương thức khai báo bộ lọc. Bây giờ cả Người dùng và OAuth2Authentication đều có thể đóng vai trò là Hiệu trưởng. Vì chúng tôi đã tính đến việc tải người dùng thông qua dữ liệu Google trong UserService trước nên ứng dụng sẽ hoạt động cho cả hai loại người dùng. Chúng tôi sửa đổi bộ điều khiển trang chính của dự án để nó chuyển hướng người dùng đã đăng nhập bằng OAuth2 tới trang ghi chú.
@GetMapping("/")
public String index(Principal principal)
{
  if(principal != null)
  {
     return "redirect:/notes";
  }
  return "index";
}

Lễ ra mắt cuối cùng của dự án

Sau những thay đổi nhỏ về mặt thẩm mỹ và thêm nút thoát, chúng tôi tiến hành khởi động dự án lần cuối.
Hãy giới thiệu tính năng đăng nhập thông thường qua email và OAuth2 vào Spring Security bằng ví dụ về dịch vụ ghi chú - 8
Hãy giới thiệu tính năng đăng nhập thông thường qua email và OAuth2 vào Spring Security bằng ví dụ về dịch vụ ghi chú - 9
Hãy giới thiệu tính năng đăng nhập thông thường qua email và OAuth2 vào Spring Security bằng ví dụ về dịch vụ ghi chú - 10
Hãy giới thiệu tính năng đăng nhập thông thường qua email và OAuth2 vào Spring Security bằng ví dụ về dịch vụ ghi chú - 11
Hãy giới thiệu tính năng đăng nhập thông thường qua email và OAuth2 vào Spring Security bằng ví dụ về dịch vụ ghi chú - 12
Hãy giới thiệu tính năng đăng nhập thông thường qua email và OAuth2 vào Spring Security bằng ví dụ về dịch vụ ghi chú - 13
Hãy giới thiệu tính năng đăng nhập thông thường qua email và OAuth2 cho Spring Security bằng ví dụ về dịch vụ ghi chú - 14
Hãy giới thiệu tính năng đăng nhập thông thường qua email và OAuth2 vào Spring Security bằng ví dụ về dịch vụ ghi chú - 15
Người dùng đăng nhập thành công cả thông qua biểu mẫu thông thường và thông qua tài khoản Google. Đây là những gì chúng tôi muốn! Tôi hy vọng bài viết này đã làm sáng tỏ một số điểm về cách tạo một ứng dụng web, bảo mật nó bằng Spring Security và kết hợp các phương thức đăng nhập khác nhau. Với mã dự án đầy đủ, bạn có thể
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION