java - 带有继承的 Spring JWT 身份验证
问题描述
将子类保存到我的数据库后,我遇到了身份验证问题。
我有三个类(Client、RetailClient 和 WholesaleClient),我想按类型注册用户。当我将行保存为客户端(父级)时,一切正常,但是当我想将对象保存为子级(RetailClient、 WholesaleClient)时,我遇到了日志记录问题(401 错误)。是否可以通过继承登录?
我的代码:
家长
@Entity
@Table(name = "clients", uniqueConstraints = {
@UniqueConstraint(columnNames = {
"username"
}),
@UniqueConstraint(columnNames = {
"email"
})
})
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(
name = "Type",
discriminatorType = DiscriminatorType.STRING
)
public class Client extends DateAudit {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotBlank
@Size(max = 40)
private String name;
@NotBlank
@Size(max = 15)
private String username;
@NaturalId
@NotBlank
@Size(max = 40)
@Email
private String email;
@NotBlank
@Size(max = 100)
private String password;
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "user_roles",
joinColumns = @JoinColumn(name = "user_id"),
inverseJoinColumns = @JoinColumn(name = "role_id"))
private Set<Role> roles = new HashSet<>();
public Client() {
}
public Client(String name, String username, String email, String password) {
this.name = name;
this.username = username;
this.email = email;
this.password = password;
}
... getters and setters
孩子
@Entity
@DiscriminatorValue("RetailClient")
public class RetailClient extends Client {
@Column(name = "First_Name")
private String firstName;
@Column(name = "Second_Name")
private String secondName;
public RetailClient(String firstName, String secondName) {
this.firstName = firstName;
this.secondName = secondName;
}
... getters and setters
控制器出现 401 错误:
RetailClient retailClient = new RetailClient("TestImie", "TestNazwisko");
retailClient.setName(signUpRequest.getName());
retailClient.setUsername(signUpRequest.getUsername());
retailClient.setEmail(signUpRequest.getEmail());
retailClient.setPassword(signUpRequest.getPassword());
retailClient.setPassword(passwordEncoder.encode(retailClient.getPassword()));
Role clientUserRole = roleRepository.findByName(RoleName.ROLE_USER)
.orElseThrow(() -> new AppException("User Role not set."));
retailClient.setRoles(Collections.singleton(clientUserRole));
Client result = clientRepository.save(retailClient);
没有错误的控制器:
Client client1 = new Client(signUpRequest.getName(), signUpRequest.getUsername(),
signUpRequest.getEmail(), signUpRequest.getPassword());
client1.setPassword(passwordEncoder.encode(client1.getPassword()));
Role userRole = roleRepository.findByName(RoleName.ROLE_USER)
.orElseThrow(() -> new AppException("User Role not set."));
client1.setRoles(Collections.singleton(userRole));
Client result = clientRepository.save(client1);
自定义用户详细信息服务:
@Service
public class CustomUserDetailsService implements UserDetailsService {
private ClientRepository clientRepository;
public CustomUserDetailsService(ClientRepository clientRepository) {
this.clientRepository = clientRepository;
}
@Override
@Transactional
public UserDetails loadUserByUsername(String usernameOrEmail)
throws UsernameNotFoundException {
Client client = clientRepository.findByUsernameOrEmail(usernameOrEmail, usernameOrEmail)
.orElseThrow(() ->
new UsernameNotFoundException("User not found with username or email : " + usernameOrEmail)
);
return UserPrincipal.create(client);
}
@Transactional
public UserDetails loadUserById(Long id) {
Client client = clientRepository.findById(id).orElseThrow(
() -> new ResourceNotFoundException("User", "id", id)
);
return UserPrincipal.create(client);
}
用户主体:
public class UserPrincipal implements UserDetails {
private Long id;
private String name;
private String username;
@JsonIgnore
private String email;
@JsonIgnore
private String password;
private Collection<? extends GrantedAuthority> authorities;
public UserPrincipal(Long id, String name, String username, String email, String password, Collection<? extends GrantedAuthority> authorities) {
this.id = id;
this.name = name;
this.username = username;
this.email = email;
this.password = password;
this.authorities = authorities;
}
public static UserPrincipal create(Client client) {
List<GrantedAuthority> authorities = client.getRoles().stream().map(role ->
new SimpleGrantedAuthority(role.getName().name())
).collect(Collectors.toList());
return new UserPrincipal(
client.getId(),
client.getName(),
client.getUsername(),
client.getEmail(),
client.getPassword(),
authorities
);
}
客户端存储库:
@Repository
public interface ClientRepository extends JpaRepository<Client, Long> {
Optional<Client> findByUsernameOrEmail(String username, String email);
Boolean existsByUsername(String username);
Boolean existsByEmail(String email);
}
你能告诉我哪里有问题吗?如果需要更多代码,我可以附上它,但请告诉我哪个类。
数据库中唯一不同的是“类型” - 其他信息是相同的。
我知道我可以将每个变量加入父类,但是可以使用继承登录吗?
编辑 - 日志:
2018-12-10 22:41:41.241 DEBUG 9499 --- [nio-8080-exec-3] org.hibernate.SQL : select * from clients c where c.username = ? or c.email = ?
2018-12-10 22:41:41.242 TRACE 9499 --- [nio-8080-exec-3] o.h.type.descriptor.sql.BasicBinder : binding parameter [2] as [VARCHAR] - [thomas]
2018-12-10 22:41:41.242 TRACE 9499 --- [nio-8080-exec-3] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [VARCHAR] - [thomas]
2018-12-10 22:41:41.248 DEBUG 9499 --- [nio-8080-exec-3] org.hibernate.SQL : select roles0_.user_id as user_id1_15_0_, roles0_.role_id as role_id2_15_0_, role1_.id as id1_14_1_, role1_.name as name2_14_1_ from user_roles roles0_ inner join roles role1_ on roles0_.role_id=role1_.id where roles0_.user_id=?
2018-12-10 22:41:41.249 TRACE 9499 --- [nio-8080-exec-3] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [BIGINT] - [1]
2018-12-10 22:41:49.718 DEBUG 9499 --- [nio-8080-exec-4] org.hibernate.SQL : select * from clients c where c.username = ? or c.email = ?
2018-12-10 22:41:49.718 TRACE 9499 --- [nio-8080-exec-4] o.h.type.descriptor.sql.BasicBinder : binding parameter [2] as [VARCHAR] - [anthony]
2018-12-10 22:41:49.718 TRACE 9499 --- [nio-8080-exec-4] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [VARCHAR] - [anthony]
第一个选择是当类型为“RetailClient”时,第二个是当我将其更改为“客户”时,然后有角色声明并且一切正常......
解决方案
您ClientRepository
只是在查询Client
哪个是父级并且找不到Child
。您应该为此编写本机查询。这将帮助您:
@Query(value = "select * from clients c where c.username = :username or c.email = :email", nativeQuery = true)
Optional<Client> findByUsernameOrEmail(@Param("username") String username, @Param("email") String email);
推荐阅读
- vtiger - 事件状态错误:添加新值并通过小部件修改它(里面有视频)
- apache-kafka - 当源集群和目标集群不在同一配置中时,Kafka Mirror Maker 不复制主题
- pyspark - Pyspark 转换:列名到行
- maven - Maven:无法执行 gpg 命令
- python - Python:线程
- ios - 无法在“'”符号后输入任何内容
- python - 正则表达式以特定格式匹配当前日期
- python - 将图像从 BGR 更改为 RGB
- react-native - 在解析模块 `react-native/Libraries/NewAppScreen` 时,发现了 Haste 包 `react-native`
- javascript - 在另一个内部创建一个 web 组件并将其附加到另一个上面是不好的做法吗?