Я обновляюсь с Java 17 до 25, Spring Framework 5.3.39 до 7.0.3.
Всякий раз, когда я пытаюсь отправить учетные данные через страницу входа, я получаю ошибку 404. Я что-то упускаю, чтобы это работало?
Spring 5 WebSecurityConfig.java
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
/**
* クラス名です。トレースに使用します。
*/
private String sClassName_ = null;
/**
* ORACLE用のハンドラの作成です。
*/
private RdbHandler handler_ = null;
/**
* ユーザーのデフォルト権限です。
*/
private List authorities_ = null;
/**
* ログインページです。
*/
private String sLoginPage_ = null;
/**
* ログアウトの遷移先URLです。
*/
private String sLogoutUrl_ = null;
/**
* ログイン成功時の遷移先URLです。
*/
private String sLoginSuccessUrl_ = null;
/**
* ログインしていないユーザー用のページです。
*/
private String[] aAnonymousPage_ = null;
/**
* ログイン必要なページです。
*/
private String[] aAuthenticatedPage_ = null;
public WebSecurityConfig() {
sClassName_ = getClass().getName();
handler_ = new RdbHandler(RdbHandler.MODE_WEB);
authorities_ = new ArrayList();
authorities_.add(new SimpleGrantedAuthority("LINIC3"));
sLoginPage_ = Linic3Property.getWebSecurity(Linic3Property.LOGINPAGE);
sLogoutUrl_ = Linic3Property.getWebSecurity(Linic3Property.LOGOUTURL);
sLoginSuccessUrl_ = Linic3Property.getWebSecurity(Linic3Property.LOGINSUCCESSURL);
// -----------------------------------------
// ログインしていないユーザー用のページ
// -----------------------------------------
String sAnonymousPage = Linic3Property.getWebSecurity(Linic3Property.ANONYMOUSPAGE);
List aAnonymousPage = splitToken(sAnonymousPage);
aAnonymousPage_ = aAnonymousPage.toArray(String[]::new);
// -----------------------------------------
// ログイン必要なページ
// -----------------------------------------
String sAuthenticatedPage = Linic3Property.getWebSecurity(Linic3Property.AUTHENTICATEDPAGE);
List aAuthenticatedPage = splitToken(sAuthenticatedPage);
aAuthenticatedPage_ = aAuthenticatedPage.toArray(String[]::new);
}
@Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
String sTraceMark = sClassName_ + ".configure():";
Trace.debug(sTraceMark + "Start!");
auth.userDetailsService(username -> {
UserMasterBean bean = new UserMasterBean();
try {
handler_.connect();
bean.setUSERID(username);
// ---------------------------------
// ユーザーマスタを取得します
// ---------------------------------
handler_.select(SQLProperty.getSelectSql("LPF300C", "LPF300C_SEL03"), bean);
if (handler_.next()) {
handler_.fetch(bean);
} else {
handler_.closeStatement();
throw new UsernameNotFoundException(username);
}
handler_.closeStatement();
if (bean.getUSERPASSWORD() == null) {
throw new UsernameNotFoundException(username);
}
// 当月ログイン回数カウントアップ
handler_.update(SQLProperty.getUpdateSql("LPF300C", "LPF300C_UPD03"), bean);
handler_.commit();
return new User(username, passwordEncoder().encode(bean.getUSERPASSWORD()), authorities_);
} catch (Exception e) {
Trace.printStackTrace(e);
} finally {
handler_.disconnect();
Trace.debug(sTraceMark + "End!");
}
throw new UsernameNotFoundException(username);
});
}
@Override
protected void configure(final HttpSecurity http) throws Exception {
http.httpBasic().disable().csrf().disable().cors().and()
.authorizeRequests()
.antMatchers(aAnonymousPage_).anonymous()
.antMatchers(aAuthenticatedPage_).authenticated()
.antMatchers("**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage(sLoginPage_)
.loginProcessingUrl(sLoginPage_)
.successHandler(authenticationSuccessHandler(sLoginSuccessUrl_))
.failureHandler(authenticationFailureHandler(sLoginPage_))
.and()
.logout()
.logoutUrl(sLogoutUrl_)
.logoutSuccessHandler(logoutSuccessHandler(sLoginPage_))
.deleteCookies("JSESSIONID");
}
@Bean
public AuthenticationSuccessHandler authenticationSuccessHandler(String sForwardTarget) {
return new jp.co.nisz.linic3.config.websecurity.AuthenticationSuccessHandler(sForwardTarget);
}
@Bean
public AuthenticationFailureHandler authenticationFailureHandler(String sForwardTarget) {
return new jp.co.nisz.linic3.config.websecurity.AuthenticationFailureHandler(sForwardTarget);
}
@Bean
public LogoutSuccessHandler logoutSuccessHandler(String sForwardTarget) {
return new jp.co.nisz.linic3.config.websecurity.LogoutSuccessHandler(sForwardTarget);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
/**
* カンマ区切りの文字列をカンマで分割し、Listへ詰めて返します。
*
* @param カンマ区切りの文字列
* @return カンマで分割された文字列を持つList
*/
private List splitToken(String sTarget) {
List aRetVal = new ArrayList();
// 文字列がnull or 空白でない場合
if (NullChecker.check(sTarget) == false) {
StringTokenizer tokens = new StringTokenizer(sTarget, ", ", false);
while (tokens.hasMoreTokens()) {
aRetVal.add(tokens.nextToken());
}
}
return aRetVal;
}
}
Весна 7 WebSecurityConfig.java (Весна 7)
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
/**
* クラス名です。トレースに使用します。
*/
private String sClassName_ = null;
/**
* ORACLE用のハンドラの作成です。
*/
private RdbHandler handler_ = null;
/**
* ユーザーのデフォルト権限です。
*/
private List authorities_ = null;
/**
* ログインページです。
*/
private String sLoginPage_ = null;
/**
* ログアウトの遷移先URLです。
*/
private String sLogoutUrl_ = null;
/**
* ログイン成功時の遷移先URLです。
*/
private String sLoginSuccessUrl_ = null;
/**
* ログインしていないユーザー用のページです。
*/
private String[] aAnonymousPage_ = null;
/**
* ログイン必要なページです。
*/
private String[] aAuthenticatedPage_ = null;
public WebSecurityConfig() {
sClassName_ = getClass().getName();
handler_ = new RdbHandler(RdbHandler.MODE_WEB);
authorities_ = new ArrayList();
authorities_.add(new SimpleGrantedAuthority("LINIC3"));
sLoginPage_ = Linic3Property.getWebSecurity(Linic3Property.LOGINPAGE);
sLogoutUrl_ = Linic3Property.getWebSecurity(Linic3Property.LOGOUTURL);
sLoginSuccessUrl_ = Linic3Property.getWebSecurity(Linic3Property.LOGINSUCCESSURL);
// -----------------------------------------
// ログインしていないユーザー用のページ
// -----------------------------------------
String sAnonymousPage = Linic3Property.getWebSecurity(Linic3Property.ANONYMOUSPAGE);
List aAnonymousPage = splitToken(sAnonymousPage);
aAnonymousPage_ = aAnonymousPage.toArray(String[]::new);
// -----------------------------------------
// ログイン必要なページ
// -----------------------------------------
String sAuthenticatedPage = Linic3Property.getWebSecurity(Linic3Property.AUTHENTICATEDPAGE);
List aAuthenticatedPage = splitToken(sAuthenticatedPage);
aAuthenticatedPage_ = aAuthenticatedPage.toArray(String[]::new);
}
@Bean
public UserDetailsService userDetailsService(PasswordEncoder passwordEncoder) {
return username -> {
String sTraceMark = sClassName_ + ".userDetailsService():";
Trace.debug(sTraceMark + "Start!");
UserMasterBean bean = new UserMasterBean();
try {
handler_.connect();
bean.setUSERID(username);
// ---------------------------------
// ユーザーマスタを取得します
// ---------------------------------
handler_.select(SQLProperty.getSelectSql("LPF300C", "LPF300C_SEL03"), bean);
if (handler_.next()) {
handler_.fetch(bean);
} else {
handler_.closeStatement();
throw new UsernameNotFoundException(username);
}
handler_.closeStatement();
if (bean.getUSERPASSWORD() == null) {
throw new UsernameNotFoundException(username);
}
// 当月ログイン回数カウントアップ
handler_.update(SQLProperty.getUpdateSql("LPF300C", "LPF300C_UPD03"), bean);
handler_.commit();
return new User(username, passwordEncoder.encode(bean.getUSERPASSWORD()), authorities_);
} catch (Exception e) {
Trace.printStackTrace(e);
} finally {
handler_.disconnect();
Trace.debug(sTraceMark + "End!");
}
throw new UsernameNotFoundException(username);
};
}
@Bean
protected SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.httpBasic(httpBasic -> httpBasic.disable())
.csrf(csrf -> csrf.disable())
.cors(cors -> cors.disable())
.authorizeHttpRequests(auth -> auth
.requestMatchers(aAnonymousPage_).anonymous()
.requestMatchers(aAuthenticatedPage_).authenticated()
.requestMatchers("/**").permitAll()
.anyRequest().authenticated())
.formLogin(form -> form
.loginPage(sLoginPage_)
.loginProcessingUrl(sLoginPage_)
.successHandler(authenticationSuccessHandler(sLoginSuccessUrl_))
.failureHandler(authenticationFailureHandler(sLoginPage_)))
.logout(logout -> logout
.logoutUrl(sLogoutUrl_)
.logoutSuccessHandler(logoutSuccessHandler(sLoginPage_))
.deleteCookies("JSESSIONID"));
return http.build();
}
@Bean
public AuthenticationManager authenticationManager(HttpSecurity http) throws Exception {
AuthenticationManagerBuilder authenticationManagerBuilder =
http.getSharedObject(AuthenticationManagerBuilder.class);
return authenticationManagerBuilder.build();
}
@Bean
public AuthenticationSuccessHandler authenticationSuccessHandler(String sForwardTarget) {
return new jp.co.nisz.linic3.config.websecurity.AuthenticationSuccessHandler(sForwardTarget);
}
@Bean
public AuthenticationFailureHandler authenticationFailureHandler(String sForwardTarget) {
return new jp.co.nisz.linic3.config.websecurity.AuthenticationFailureHandler(sForwardTarget);
}
@Bean
public LogoutSuccessHandler logoutSuccessHandler(String sForwardTarget) {
return new jp.co.nisz.linic3.config.websecurity.LogoutSuccessHandler(sForwardTarget);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
/**
* カンマ区切りの文字列をカンマで分割し、Listへ詰めて返します。
*
* @param カンマ区切りの文字列
* @return カンマで分割された文字列を持つList
*/
private List splitToken(String sTarget) {
List aRetVal = new ArrayList();
// 文字列がnull or 空白でない場合
if (NullChecker.check(sTarget) == false) {
StringTokenizer tokens = new StringTokenizer(sTarget, ", ", false);
while (tokens.hasMoreTokens()) {
aRetVal.add(tokens.nextToken());
}
}
return aRetVal;
}
}
login.html
ユーザーID
パスワード
Подробнее здесь: https://stackoverflow.com/questions/798 ... gin-submit
Spring Security с 5 на 7 миграция, ошибка 404, отправка входа в систему ⇐ JAVA
Программисты JAVA общаются здесь
1769507900
Anonymous
Я обновляюсь с Java 17 до 25, Spring Framework 5.3.39 до 7.0.3.
Всякий раз, когда я пытаюсь отправить учетные данные через страницу входа, я получаю ошибку 404. Я что-то упускаю, чтобы это работало?
Spring 5 WebSecurityConfig.java
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
/**
* クラス名です。トレースに使用します。
*/
private String sClassName_ = null;
/**
* ORACLE用のハンドラの作成です。
*/
private RdbHandler handler_ = null;
/**
* ユーザーのデフォルト権限です。
*/
private List authorities_ = null;
/**
* ログインページです。
*/
private String sLoginPage_ = null;
/**
* ログアウトの遷移先URLです。
*/
private String sLogoutUrl_ = null;
/**
* ログイン成功時の遷移先URLです。
*/
private String sLoginSuccessUrl_ = null;
/**
* ログインしていないユーザー用のページです。
*/
private String[] aAnonymousPage_ = null;
/**
* ログイン必要なページです。
*/
private String[] aAuthenticatedPage_ = null;
public WebSecurityConfig() {
sClassName_ = getClass().getName();
handler_ = new RdbHandler(RdbHandler.MODE_WEB);
authorities_ = new ArrayList();
authorities_.add(new SimpleGrantedAuthority("LINIC3"));
sLoginPage_ = Linic3Property.getWebSecurity(Linic3Property.LOGINPAGE);
sLogoutUrl_ = Linic3Property.getWebSecurity(Linic3Property.LOGOUTURL);
sLoginSuccessUrl_ = Linic3Property.getWebSecurity(Linic3Property.LOGINSUCCESSURL);
// -----------------------------------------
// ログインしていないユーザー用のページ
// -----------------------------------------
String sAnonymousPage = Linic3Property.getWebSecurity(Linic3Property.ANONYMOUSPAGE);
List aAnonymousPage = splitToken(sAnonymousPage);
aAnonymousPage_ = aAnonymousPage.toArray(String[]::new);
// -----------------------------------------
// ログイン必要なページ
// -----------------------------------------
String sAuthenticatedPage = Linic3Property.getWebSecurity(Linic3Property.AUTHENTICATEDPAGE);
List aAuthenticatedPage = splitToken(sAuthenticatedPage);
aAuthenticatedPage_ = aAuthenticatedPage.toArray(String[]::new);
}
@Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
String sTraceMark = sClassName_ + ".configure():";
Trace.debug(sTraceMark + "Start!");
auth.userDetailsService(username -> {
UserMasterBean bean = new UserMasterBean();
try {
handler_.connect();
bean.setUSERID(username);
// ---------------------------------
// ユーザーマスタを取得します
// ---------------------------------
handler_.select(SQLProperty.getSelectSql("LPF300C", "LPF300C_SEL03"), bean);
if (handler_.next()) {
handler_.fetch(bean);
} else {
handler_.closeStatement();
throw new UsernameNotFoundException(username);
}
handler_.closeStatement();
if (bean.getUSERPASSWORD() == null) {
throw new UsernameNotFoundException(username);
}
// 当月ログイン回数カウントアップ
handler_.update(SQLProperty.getUpdateSql("LPF300C", "LPF300C_UPD03"), bean);
handler_.commit();
return new User(username, passwordEncoder().encode(bean.getUSERPASSWORD()), authorities_);
} catch (Exception e) {
Trace.printStackTrace(e);
} finally {
handler_.disconnect();
Trace.debug(sTraceMark + "End!");
}
throw new UsernameNotFoundException(username);
});
}
@Override
protected void configure(final HttpSecurity http) throws Exception {
http.httpBasic().disable().csrf().disable().cors().and()
.authorizeRequests()
.antMatchers(aAnonymousPage_).anonymous()
.antMatchers(aAuthenticatedPage_).authenticated()
.antMatchers("**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage(sLoginPage_)
.loginProcessingUrl(sLoginPage_)
.successHandler(authenticationSuccessHandler(sLoginSuccessUrl_))
.failureHandler(authenticationFailureHandler(sLoginPage_))
.and()
.logout()
.logoutUrl(sLogoutUrl_)
.logoutSuccessHandler(logoutSuccessHandler(sLoginPage_))
.deleteCookies("JSESSIONID");
}
@Bean
public AuthenticationSuccessHandler authenticationSuccessHandler(String sForwardTarget) {
return new jp.co.nisz.linic3.config.websecurity.AuthenticationSuccessHandler(sForwardTarget);
}
@Bean
public AuthenticationFailureHandler authenticationFailureHandler(String sForwardTarget) {
return new jp.co.nisz.linic3.config.websecurity.AuthenticationFailureHandler(sForwardTarget);
}
@Bean
public LogoutSuccessHandler logoutSuccessHandler(String sForwardTarget) {
return new jp.co.nisz.linic3.config.websecurity.LogoutSuccessHandler(sForwardTarget);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
/**
* カンマ区切りの文字列をカンマで分割し、Listへ詰めて返します。
*
* @param カンマ区切りの文字列
* @return カンマで分割された文字列を持つList
*/
private List splitToken(String sTarget) {
List aRetVal = new ArrayList();
// 文字列がnull or 空白でない場合
if (NullChecker.check(sTarget) == false) {
StringTokenizer tokens = new StringTokenizer(sTarget, ", ", false);
while (tokens.hasMoreTokens()) {
aRetVal.add(tokens.nextToken());
}
}
return aRetVal;
}
}
Весна 7 WebSecurityConfig.java (Весна 7)
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
/**
* クラス名です。トレースに使用します。
*/
private String sClassName_ = null;
/**
* ORACLE用のハンドラの作成です。
*/
private RdbHandler handler_ = null;
/**
* ユーザーのデフォルト権限です。
*/
private List authorities_ = null;
/**
* ログインページです。
*/
private String sLoginPage_ = null;
/**
* ログアウトの遷移先URLです。
*/
private String sLogoutUrl_ = null;
/**
* ログイン成功時の遷移先URLです。
*/
private String sLoginSuccessUrl_ = null;
/**
* ログインしていないユーザー用のページです。
*/
private String[] aAnonymousPage_ = null;
/**
* ログイン必要なページです。
*/
private String[] aAuthenticatedPage_ = null;
public WebSecurityConfig() {
sClassName_ = getClass().getName();
handler_ = new RdbHandler(RdbHandler.MODE_WEB);
authorities_ = new ArrayList();
authorities_.add(new SimpleGrantedAuthority("LINIC3"));
sLoginPage_ = Linic3Property.getWebSecurity(Linic3Property.LOGINPAGE);
sLogoutUrl_ = Linic3Property.getWebSecurity(Linic3Property.LOGOUTURL);
sLoginSuccessUrl_ = Linic3Property.getWebSecurity(Linic3Property.LOGINSUCCESSURL);
// -----------------------------------------
// ログインしていないユーザー用のページ
// -----------------------------------------
String sAnonymousPage = Linic3Property.getWebSecurity(Linic3Property.ANONYMOUSPAGE);
List aAnonymousPage = splitToken(sAnonymousPage);
aAnonymousPage_ = aAnonymousPage.toArray(String[]::new);
// -----------------------------------------
// ログイン必要なページ
// -----------------------------------------
String sAuthenticatedPage = Linic3Property.getWebSecurity(Linic3Property.AUTHENTICATEDPAGE);
List aAuthenticatedPage = splitToken(sAuthenticatedPage);
aAuthenticatedPage_ = aAuthenticatedPage.toArray(String[]::new);
}
@Bean
public UserDetailsService userDetailsService(PasswordEncoder passwordEncoder) {
return username -> {
String sTraceMark = sClassName_ + ".userDetailsService():";
Trace.debug(sTraceMark + "Start!");
UserMasterBean bean = new UserMasterBean();
try {
handler_.connect();
bean.setUSERID(username);
// ---------------------------------
// ユーザーマスタを取得します
// ---------------------------------
handler_.select(SQLProperty.getSelectSql("LPF300C", "LPF300C_SEL03"), bean);
if (handler_.next()) {
handler_.fetch(bean);
} else {
handler_.closeStatement();
throw new UsernameNotFoundException(username);
}
handler_.closeStatement();
if (bean.getUSERPASSWORD() == null) {
throw new UsernameNotFoundException(username);
}
// 当月ログイン回数カウントアップ
handler_.update(SQLProperty.getUpdateSql("LPF300C", "LPF300C_UPD03"), bean);
handler_.commit();
return new User(username, passwordEncoder.encode(bean.getUSERPASSWORD()), authorities_);
} catch (Exception e) {
Trace.printStackTrace(e);
} finally {
handler_.disconnect();
Trace.debug(sTraceMark + "End!");
}
throw new UsernameNotFoundException(username);
};
}
@Bean
protected SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.httpBasic(httpBasic -> httpBasic.disable())
.csrf(csrf -> csrf.disable())
.cors(cors -> cors.disable())
.authorizeHttpRequests(auth -> auth
.requestMatchers(aAnonymousPage_).anonymous()
.requestMatchers(aAuthenticatedPage_).authenticated()
.requestMatchers("/**").permitAll()
.anyRequest().authenticated())
.formLogin(form -> form
.loginPage(sLoginPage_)
.loginProcessingUrl(sLoginPage_)
.successHandler(authenticationSuccessHandler(sLoginSuccessUrl_))
.failureHandler(authenticationFailureHandler(sLoginPage_)))
.logout(logout -> logout
.logoutUrl(sLogoutUrl_)
.logoutSuccessHandler(logoutSuccessHandler(sLoginPage_))
.deleteCookies("JSESSIONID"));
return http.build();
}
@Bean
public AuthenticationManager authenticationManager(HttpSecurity http) throws Exception {
AuthenticationManagerBuilder authenticationManagerBuilder =
http.getSharedObject(AuthenticationManagerBuilder.class);
return authenticationManagerBuilder.build();
}
@Bean
public AuthenticationSuccessHandler authenticationSuccessHandler(String sForwardTarget) {
return new jp.co.nisz.linic3.config.websecurity.AuthenticationSuccessHandler(sForwardTarget);
}
@Bean
public AuthenticationFailureHandler authenticationFailureHandler(String sForwardTarget) {
return new jp.co.nisz.linic3.config.websecurity.AuthenticationFailureHandler(sForwardTarget);
}
@Bean
public LogoutSuccessHandler logoutSuccessHandler(String sForwardTarget) {
return new jp.co.nisz.linic3.config.websecurity.LogoutSuccessHandler(sForwardTarget);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
/**
* カンマ区切りの文字列をカンマで分割し、Listへ詰めて返します。
*
* @param カンマ区切りの文字列
* @return カンマで分割された文字列を持つList
*/
private List splitToken(String sTarget) {
List aRetVal = new ArrayList();
// 文字列がnull or 空白でない場合
if (NullChecker.check(sTarget) == false) {
StringTokenizer tokens = new StringTokenizer(sTarget, ", ", false);
while (tokens.hasMoreTokens()) {
aRetVal.add(tokens.nextToken());
}
}
return aRetVal;
}
}
login.html
ユーザーID
パスワード
Подробнее здесь: [url]https://stackoverflow.com/questions/79876908/spring-security-from-5-to-7-migration-error-404-login-submit[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия