带有 JWT 的 Java Spring 多个 @Autowired MongoRepository 用法
Posted
技术标签:
【中文标题】带有 JWT 的 Java Spring 多个 @Autowired MongoRepository 用法【英文标题】:Java Spring Multiple @Autowired MongoRepository Usages with JWT 【发布时间】:2019-08-09 11:39:40 【问题描述】:JWTAuthenticationFilter.java 中的successfulAuthentication 函数给出了一个空指针异常。你明白为什么这会是一个问题吗?使用同一个 bean 进行自动装配有问题吗?
这是我目前的项目结构:
-com
-register
-RegisterController.java
-security
-JWTAuthenticationFilter.java
-JWTAuthorizationFilter.java
-SecurityConstants.java
-WebSecurity.java
-user
-User.java
-UserRepository.java
-UserService.java
-Application.java
Application.java
@Configuration
@SpringBootApplication
public class Application
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder()
return new BCryptPasswordEncoder();
public static void main(String[] args)
SpringApplication.run(Application.class, args);
UserRepository.java
@Repository
public interface UserRepository extends MongoRepository<User, String>
User findByUsername(String name);
User findByEmail(String Email);
User findBy_id(ObjectId id);
用户服务.java
@Service
public class UserService implements UserDetailsService
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
User user = this.userRepository.findByUsername(username);
if(user == null)
return null;
List<SimpleGrantedAuthority> authorities = Arrays.asList(new SimpleGrantedAuthority("user"));
return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), authorities);
public User getUserByUsername(String username)
return this.userRepository.findByUsername(username);
public User getUserBy_id(ObjectId _id)
return userRepository.findBy_id(_id);
public void saveUser(User newUser)
userRepository.save(newUser);
用户.java
@Document
public final class User
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private ObjectId _id;
private String email;
private String username;
private String password;
private AccountProperties accountProperties;
private Address address;
private List<Pet> pets = new ArrayList<>();
private String phoneNumber;
public User()
public User(@JsonProperty("email") String email, @JsonProperty("username") String username,
@JsonProperty("password") String password)
this.email = email;
this.username = username;
this.password = password;
public String get_id() return _id.toHexString();
getters and setters() ...
JWTAuthenticationFilter.java
public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter
@Autowired
private UserRepository userRepo;
private AuthenticationManager authenticationManager;
JWTAuthenticationFilter(AuthenticationManager authenticationManager)
this.authenticationManager = authenticationManager;
@Override
public Authentication attemptAuthentication(HttpServletRequest req,
HttpServletResponse res) throws AuthenticationException
try
User creds = new ObjectMapper()
.readValue(req.getInputStream(), User.class);
return authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(
creds.getUsername(),
creds.getPassword(),
new ArrayList<>())
);
catch (IOException e)
throw new RuntimeException(e);
@Override
protected void successfulAuthentication(HttpServletRequest req,
HttpServletResponse res,
FilterChain chain,
Authentication auth) throws IOException, ServletException
String username = ((org.springframework.security.core.userdetails.User) auth.getPrincipal()).getUsername();
String token = JWT.create()
.withSubject(username)
.withExpiresAt(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
.sign(HMAC512(SECRET.getBytes()));
res.addHeader(HEADER_STRING, TOKEN_PREFIX + token);
User u = uRepo.findByUsername("admin");
res.getWriter().write(
"\"" + SecurityConstants.HEADER_STRING + "\":\"" + SecurityConstants.TOKEN_PREFIX+token + "\"," +
"\"" + "ObjectID" + "\":\"" + u.get_id() + "\""
);
JWTAuthorizationFilter.java
public class JWTAuthorizationFilter extends BasicAuthenticationFilter
public JWTAuthorizationFilter(AuthenticationManager authManager)
super(authManager);
@Override
protected void doFilterInternal(HttpServletRequest req,
HttpServletResponse res,
FilterChain chain) throws IOException, ServletException
String header = req.getHeader(HEADER_STRING);
if (header == null || !header.startsWith(TOKEN_PREFIX))
chain.doFilter(req, res);
return;
UsernamePasswordAuthenticationToken authentication = getAuthentication(req);
SecurityContextHolder.getContext().setAuthentication(authentication);
chain.doFilter(req, res);
private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request)
String token = request.getHeader(HEADER_STRING);
if (token != null)
// parse the token.
String user = JWT.require(Algorithm.HMAC512(SECRET.getBytes()))
.build()
.verify(token.replace(TOKEN_PREFIX, ""))
.getSubject();
if (user != null)
return new UsernamePasswordAuthenticationToken(user, null, new ArrayList<>());
return null;
return null;
WebSecurity.java
@EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter
@Autowired
private UserService userDetailsService;
@Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
@Override
protected void configure(HttpSecurity http) throws Exception
http.cors().and().csrf().disable().authorizeRequests()
.antMatchers(HttpMethod.POST, SIGN_UP_URL).permitAll()
.anyRequest().authenticated()
.and()
.addFilter(new JWTAuthenticationFilter(authenticationManager()))
.addFilter(new JWTAuthorizationFilter(authenticationManager()))
// this disables session creation on Spring Security
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS );
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception auth.userDetailsService(this.userDetailsService).passwordEncoder(this.bCryptPasswordEncoder);
@Bean
CorsConfigurationSource corsConfigurationSource()
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
return source;
SecurityConstants.java
public class SecurityConstants
public static final String SECRET = "SecretKeyToGenJWTs";
public static final long EXPIRATION_TIME = 864_000_000; // 10 days
public static final String TOKEN_PREFIX = "Bearer ";
public static final String HEADER_STRING = "Authorization";
public static final String SIGN_UP_URL = "/users/sign-up";
RegisterController.java
@RestController
@RequestMapping("/users")
public class RegisterController
@Autowired
private UserService userService;
@Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
@PostMapping("/sign-up")
public void signUp(@RequestBody User user)
if (user.getPassword() == null || user.getUsername() == null)
return;
user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
userService.saveUser(user);
【问题讨论】:
【参考方案1】:不确定这是否是您的问题的根本原因,但我从未在主应用程序中看到 @Configuration
。我会尝试将其移至单独的配置类,看看是否有帮助
【讨论】:
我对Java Spring不是太熟悉,所以你知道我们是否需要一个配置类吗?如果是这样,WebSecurity 类是否可以使用 @Configuration 进行注释? 您应该能够将@Configuration
添加到 WebSecurity 类中,我在我团队的一个 java 项目中就有了。如果我在使用 @Configuration
注释的类中使用 @Autowired
,我的 IDE 会抱怨,因此这可能不适用于您的场景。【参考方案2】:
使用@Component 注释JWTAuthenticationFilter 或在配置文件中添加@Bean。好像没有创建对象
【讨论】:
【参考方案3】:问题是你没有将JWTAuthenticationFilter定义为Bean
,所以spring不会在里面注入依赖。
您可以手动在过滤器中获取 bean。来自 GenericFilterBean javadoc:
这个通用过滤器基类不依赖于 Spring org.springframework.context.ApplicationContext 概念。过滤器通常不加载自己的上下文,而是从 Spring 根应用程序上下文访问服务 bean,可通过过滤器的 ServletContext 访问(参见 org.springframework.web.context.support.WebApplicationContextUtils)。
或者你可以把它变成bean。但如果您使用的是 Spring Boot,请考虑:
Spring Security 内部的所有过滤器对于容器来说都是未知的这一事实很重要,尤其是在 Spring Boot 应用程序中,默认情况下,所有 Filter 类型的 @Beans 都会自动注册到容器中。因此,如果您想将自定义过滤器添加到安全链中,则需要不将其设为 @Bean 或将其包装在显式禁用容器注册的 FilterRegistrationBean 中。
【讨论】:
以上是关于带有 JWT 的 Java Spring 多个 @Autowired MongoRepository 用法的主要内容,如果未能解决你的问题,请参考以下文章
多个WebSecurityConfigurerAdapters:spring security中的JWT认证和表单登录
带有 spring-boot 和 spring-security 的 JWT
带有 JWT 令牌的 Spring Security 在每个请求上加载 spring UserDetails 对象
用于 REST API 的带有 JWT 的 Spring Security
带有 JWT 令牌的 Spring Security 和 Websocket
带有 JWT AuthenticationCredentialsNotFoundException 的 Spring 安全配置