我是编程新手,尝试根据手册制作一个简单的应用程序,实现用户、角色和权限。我使用 Sprint 3.3.3 和 Java 17。
手册建议创建一个 Loader 类,该类将在构建应用程序时填充数据库。因此,无需求助于纯 SQL,就可以创建第一个管理员、创建角色和角色权限。
SetupDataLoader
类实现ApplicationListener<ContextRefreshedEvent>
接口。该类用 @Component 注释进行标记。我还尝试了 onApplicationEvent 方法来用注释 @EventListener 进行标记。
但是当APP启动时,类中的代码并没有被执行。每次启动后,我都会检查 db 的内容,发现 User 表中没有添加新行。我还尝试从该代码块向控制台输出一条消息 - 它没有输出。
我的应用程序
实体
@Entity
@Table(name = "users")
@Data
public class UserEntity {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Long id;
@Column(name = "login")
private String login;
@Column(name = "password")
private String password;
@ManyToMany
@JoinTable(
name = "users_roles",
joinColumns = @JoinColumn(
name = "user_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(
name = "role_id", referencedColumnName = "id"))
private Collection<RoleEntity> roles;
public UserEntity() {}
}
@Entity
@Table(name = "roles")
@Data
public class RoleEntity {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Long id;
@Column(name = "name")
private String name;
@ManyToMany
@JoinTable(
name = "roles_privileges",
joinColumns = @JoinColumn(
name = "role_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(
name = "privilege_id", referencedColumnName = "id"))
private Collection<PrivilegeEntity> privileges;
public RoleEntity() {}
public RoleEntity(final String name) {
this.name = name;
}
}
@Entity
@Table(name = "priveleges")
@Data
public class PrivilegeEntity {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(name = "name")
private String name;
@ManyToMany(mappedBy = "privileges")
private Collection<RoleEntity> roles;
public PrivilegeEntity() {}
public PrivilegeEntity(final String name) {
this.name = name;
}
}
回购
public interface UserRepo extends CrudRepository<UserEntity, Long> {
Optional<UserEntity> findByLogin (String login);
}
public interface RoleRepo extends CrudRepository<RoleEntity, Long> {
Optional<RoleEntity> findByName(String name);
}
public interface PrivilegeRepo extends CrudRepository<PrivilegeEntity, Long> {
Optional<PrivilegeEntity> findByName(String name);
}
顺序设置:
@EnableWebSecurity
@Configuration
public class SequrityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(AbstractHttpConfigurer::disable)
.securityContext((securityContext) -> securityContext.requireExplicitSave(true))
.authorizeHttpRequests(authorize -> authorize
.requestMatchers(HttpMethod.GET, "/roleHierarchy")
.hasRole("STAFF"));
return http.build();
}
@Bean
public SecurityExpressionHandler<FilterInvocation> customWebSecurityExpressionHandler() {
DefaultWebSecurityExpressionHandler expressionHandler = new DefaultWebSecurityExpressionHandler();
expressionHandler.setRoleHierarchy(roleHierarchy());
return expressionHandler;
}
@Bean
public RoleHierarchy roleHierarchy() {
RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
String hierarchy = "ROLE_ADMIN > ROLE_MODER \n ROLE_MODER > ROLE_STAFF";
roleHierarchy.setHierarchy(hierarchy);
return roleHierarchy;
}
}
最后
@Component
public class SetupDataLoader implements ApplicationListener<ContextRefreshedEvent> {
private boolean alreadySetup = false;
@Autowired
UserRepo userRepo;
@Autowired
RoleRepo roleRepo;
@Autowired
PrivilegeRepo privilegeRepo;
@Autowired
PasswordEncoder passwordEncoder;
// API
@Override
@Transactional
public void onApplicationEvent(final @NonNull ContextRefreshedEvent event) {
if (alreadySetup) {
return;
}
// == create init privileges
final PrivilegeEntity readPrivilege = createPrivilege("READ_PRIVILEGE");
final PrivilegeEntity userWritePrivilege = createPrivilege("USER_WRITE_PRIVILEGE");
final PrivilegeEntity switchStatePrivilege = createPrivilege("CHANGE_STATE_PRIVILEGE");
final PrivilegeEntity switchWritePrivilege = createPrivilege("SWITCH_WRITE_PRIVILEGE");
final PrivilegeEntity commentWritePrivilege = createPrivilege("COMMENT_WRITE_PRIVILEGE");
// == create init roles;
final List<PrivilegeEntity> adminPrivileges = new ArrayList<>(Arrays
.asList(readPrivilege,
userWritePrivilege,
switchStatePrivilege,
switchWritePrivilege,
commentWritePrivilege));
final List<PrivilegeEntity> moderPrivileges = new ArrayList<>(Arrays
.asList(readPrivilege,
switchWritePrivilege,
commentWritePrivilege));
final List<PrivilegeEntity> staffPrivileges = new ArrayList<>(Arrays.asList(readPrivilege));
final RoleEntity adminRole = createRole("ROLE_ADMIN", adminPrivileges);
createRole("ROLE_MODER", moderPrivileges);
createRole("ROLE_STAFF", staffPrivileges);
// == create init users FIRST ADMIN in db
createUser("ADMIN", "ADMIN", new ArrayList<>(Arrays.asList(adminRole)));
alreadySetup = true;
}
@Transactional
public PrivilegeEntity createPrivilege(final String name) {
Optional<PrivilegeEntity> optPrivilege = privilegeRepo.findByName(name);
PrivilegeEntity privilege;
if (optPrivilege.isPresent())
privilege = optPrivilege.get();
else {
privilege = new PrivilegeEntity(name);
privilege = privilegeRepo.save(privilege);
}
return privilege;
}
@Transactional
public RoleEntity createRole(final String name, final Collection<PrivilegeEntity> privileges) {
Optional<RoleEntity> optRole = roleRepo.findByName(name);
RoleEntity role;
if (optRole.isPresent())
role = optRole.get();
else {
role = new RoleEntity(name);
}
role.setPrivileges(privileges);
role = roleRepo.save(role);
return role;
}
@Transactional
public UserEntity createUser(final String login, final String password, final Collection<RoleEntity> roles) {
Optional<UserEntity> optUser = userRepo.findByLogin(login);
UserEntity user;
if (optUser.isPresent())
user = optUser.get();
else {
user = new UserEntity();
user.setLogin(login);
user.setPassword(passwordEncoder.encode(password));
}
user.setRoles(roles);
user = userRepo.save(user);
return user;
}
}
我尝试了互联网上的各种解决方案,但每次尝试后我都会检查我的数据库,一切都是一样的:
prototype=# select * from users;
id | login | password
----+-------+----------
(0 rows)
请告诉我为什么
SetapDataLoader.java
中的代码没有被执行?
只需将此类添加到您的应用程序中,然后检查日志中是否出现“应用程序就绪”消息即可。
@Component
public class ApplicationReadyEventDemo {
private static final Logger LOGGER = LoggerFactory.getLogger(ApplicationReadyEventDemo.class);
@EventListener(ApplicationReadyEvent.class)
public void onApplicationReady(ApplicationReadyEvent event) {
LOGGER.info("Application ready");
}
}