我是jHipster的新手,我正尝试将用户与公司ID相关联,以根据所述公司ID限制他们有权访问的实体。
我希望能够使用SecurityContext存储我的UserDetails的自定义实现。 我已按照这封信进行了多次教程,但似乎无法正常运行:SecurityContext返回的对象始终为org.springframework.security.core.userdetails.User类型,因此无法将其转换为实现的UserDetails类
DomainUserDetailsService.java
@Service("domainUserDetailsService")
public class DomainUserDetailsService implements UserDetailsService {
private final Logger log = LoggerFactory.getLogger(DomainUserDetailsService.class);
private UserRepository userRepository;
public DomainUserDetailsService(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
@Transactional(readOnly = true)
public UserDetails loadUserByUsername(final String login) {
log.debug("Authenticating {}", login);
User user = userRepository.findOneWithAuthoritiesByEmail(login).get();
return new UserDetails(user, 22L);
}
UserDetails.java
public class UserDetails implements org.springframework.security.core.userdetails.UserDetails {
private User user;
private Long companyId = 0L;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Long getCompanyId() {
return companyId;
}
public void setCompanyId(Long companyId) {
this.companyId = companyId;
}
public UserDetails(User user, Long companyId) {
this.user = user;
this.companyId = companyId;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return user.getAuthorities().stream().map(authority -> new SimpleGrantedAuthority(authority.getName().toString())).collect(Collectors.toList());
}
public Long getId() {
return user.getId();
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.getLogin();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
public User getUserDetails() {
return user;
}
}
SecurityConfiguration.java
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
@Import(SecurityProblemSupport.class)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private final AuthenticationManagerBuilder authenticationManagerBuilder;
private final UserDetailsService userDetailsService;
private final TokenProvider tokenProvider;
private final CorsFilter corsFilter;
private final SecurityProblemSupport problemSupport;
public SecurityConfiguration(AuthenticationManagerBuilder authenticationManagerBuilder, @Qualifier("domainUserDetailsService") UserDetailsService userDetailsService, TokenProvider tokenProvider, CorsFilter corsFilter, SecurityProblemSupport problemSupport) {
this.authenticationManagerBuilder = authenticationManagerBuilder;
this.userDetailsService = userDetailsService;
this.tokenProvider = tokenProvider;
this.corsFilter = corsFilter;
this.problemSupport = problemSupport;
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
......
SecurityUtils.java
public static UserDetails getCurrentUserDetail() {
SecurityContext securityContext = SecurityContextHolder.getContext();
Authentication authentication = securityContext.getAuthentication();
if (authentication != null) {
if (authentication.getPrincipal() instanceof UserDetails) {
UserDetails springSecurityUser = (UserDetails) authentication.getPrincipal();
return springSecurityUser;
}
}
return null;
}
问题在于,在SecurityUtils中,authentication.getPrincipal()。getClass()始终属于类 org.springframework.security.core.userdetails.User 。 我希望它的类型为 UserDetails 。
编辑 代码确实通过DomainUserDetailsService,正如我在日志中看到的那样。
我相信问题与 createToken 期间TokenProvider.java中的身份验证有关,在UserJWTController.java
中进行用户身份验证时会调用答案 0 :(得分:0)
您应该覆盖configure(AuthenticationManagerBuilder auth)
,而不是@Autowired public void configureGlobal
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
答案 1 :(得分:0)
我也遇到了同样的问题,我通过对TokenProvider.createToken和TokenProvider.getAuthentication方法进行了一些更新来处理它。想法是在 createToken 方法中将租户(在您的情况下为公司)ID或任何其他变量保存在JWT Token中,然后在 getAuthentication 方法中提取它们。下面是我的方法的代码:
Registering
Registered
all_done()
现在我们可以从JWT令牌中获取这些变量
public String createToken(Authentication authentication, boolean rememberMe, String channel) {
String authorities = authentication.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.joining(","));
long now = (new Date()).getTime();
Date validity;
if (rememberMe) {
validity = new Date(now + this.tokenValidityInMillisecondsForRememberMe);
} else {
validity = new Date(now + this.tokenValidityInMilliseconds);
}
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
Long userPkId = null;
Long tenantId = null;
if (auth != null) {
Object principal = auth.getPrincipal();
if (principal instanceof DomainUserDetails) {
DomainUserDetails domainUserDetails = (DomainUserDetails) principal;
tenantId = domainUserDetails.getTenantId();
userPkId = domainUserDetails.getId();
}
}
return Jwts.builder()
.setSubject(authentication.getName())
.claim(AUTHORITIES_KEY, authorities)
.claim(USER_ID_KEY, userPkId)
.claim(TENANT_KEY, tenantId)
.claim(CHANNEL_KEY, channel)
.signWith(key, SignatureAlgorithm.HS512)
.setExpiration(validity)
.compact();
}