我正在使用spring boot(使用JWT和spring security),我的目标是将令牌中经过身份验证的用户的ID发送到angular5(前端)。
这是JWTAuthenticationFilter.java
public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private AuthenticationManager authenticationManager;
@Autowired
private UserRepo userRepo;
@Autowired
private AccountService accountService;
@Autowired
public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
@Override
@Autowired
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
super.setAuthenticationManager(authenticationManager);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
AppUser appUser = null;
try {
appUser=new ObjectMapper().readValue(request.getInputStream(),AppUser.class);
} catch (IOException e) {
throw new RuntimeException(e.getMessage());
}
return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(appUser.getUsername(),appUser.getPassword()));
}
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
User springUser = (User)authResult.getPrincipal();
String jwt = Jwts.builder()
.setSubject(springUser.getUsername())
.setExpiration(new Date(System.currentTimeMillis()+SecurityConstants.EXPIRATION_TIME))
.signWith(SignatureAlgorithm.HS256,SecurityConstants.SECRET)
.claim("roles",springUser.getAuthorities())
.compact();
AppUser app = userRepo.findByUsername(springUser.getUsername());
Long id = app.getId();
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonJwt = objectMapper.readTree(jwt);
((ObjectNode)jsonJwt).put("userId", id);
response.addHeader(SecurityConstants.HEADER_STRING,SecurityConstants.TOKEN_PREFIX+objectMapper.writeValueAsString(jsonJwt));
}
}
这是JWTAutorizationFilter.java
package interv.Web.service;
import interv.Web.security.SecurityConstants;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
public class JWTAutorizationFilter extends OncePerRequestFilter{
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
httpServletResponse.addHeader("Access-Control-Allow-Origin","*");
httpServletResponse.addHeader("Access-Control-Allow-Headers", " Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers, Authorization");
httpServletResponse.addHeader("Access-Control-Expose-Headers",
"Access-Control-Allow-Origin, Access-Control-Allow-Credentials,Authorization");
httpServletResponse.addHeader("Access-Control-Allow-Methods","GET,PUT,POST,DELETE");
String jwtToken = httpServletRequest.getHeader(SecurityConstants.HEADER_STRING);
if(httpServletRequest.getMethod().equals("OPTIONS")){
httpServletResponse.setStatus(httpServletResponse.SC_OK);
}
else {
if(jwtToken==null || !jwtToken.startsWith(SecurityConstants.TOKEN_PREFIX)){
filterChain.doFilter(httpServletRequest,httpServletResponse);
return ;
}
Claims claims = Jwts.parser()
.setSigningKey(SecurityConstants.SECRET)
.parseClaimsJws(jwtToken.replace(SecurityConstants.TOKEN_PREFIX,""))
.getBody();
String username = claims.getSubject();
ArrayList<Map<String,String>> roles = (ArrayList<Map<String,String>>)claims.get("roles");
Collection<GrantedAuthority> authorities = new ArrayList<>();
roles.forEach(r->{
authorities.add(new SimpleGrantedAuthority(r.get("authority")));
});
UsernamePasswordAuthenticationToken authenticationToken=
new UsernamePasswordAuthenticationToken(username,null,authorities);
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
filterChain.doFilter(httpServletRequest,httpServletResponse);
}
}
}
在运行应用程序时我没有收到任何错误,但是当我尝试进行身份验证时,我在控制台中收到了这个奇怪的错误:
ERROR 4980 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception
com.fasterxml.jackson.core.JsonParseException: Unrecognized token 'eyJhbGciOiJIUzI1NiJ9': was expecting ('true', 'false' or 'null')
at [Source: eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsImV4cCI6MTUyNzUyMjQxNywicm9sZXMiOlt7ImF1dGhvcml0eSI6IkFETUlOIn1dfQ.BtaWfqSy9xyDdZrEsJD6iJRVLyTpHEVGYL1NVR670Ts; line: 1, column: 21]
at com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:1702) ~[jackson-core-2.8.10.jar:2.8.10]
at com.fasterxml.jackson.core.base.ParserMinimalBase._reportError(ParserMinimalBase.java:558) ~[jackson-core-2.8.10.jar:2.8.10]
at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._reportInvalidToken(ReaderBasedJsonParser.java:2839) ~[jackson-core-2.8.10.jar:2.8.10]
at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._handleOddValue(ReaderBasedJsonParser.java:1903) ~[jackson-core-2.8.10.jar:2.8.10]
at com.fasterxml.jackson.core.json.ReaderBasedJsonParser.nextToken(ReaderBasedJsonParser.java:749) ~[jackson-core-2.8.10.jar:2.8.10]
at com.fasterxml.jackson.databind.ObjectMapper._initForReading(ObjectMapper.java:3850) ~[jackson-databind-2.8.10.jar:2.8.10]
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3799) ~[jackson-databind-2.8.10.jar:2.8.10]
at com.fasterxml.jackson.databind.ObjectMapper.readTree(ObjectMapper.java:2397) ~[jackson-databind-2.8.10.jar:2.8.10]
at interv.Web.security.JWTAuthenticationFilter.successfulAuthentication(JWTAuthenticationFilter.java:83) ~[classes/:na]
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:240) ~[spring-security-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[spring-security-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at interv.Web.service.JWTAutorizationFilter.doFilterInternal(JWTAutorizationFilter.java:43) ~[classes/:na]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.14.RELEASE.jar:4.3.14.RELEASE]
在Arc扩展中:
{
"timestamp": 1526663679085,
"status": 500,
"error": "Internal Server Error",
"exception": "com.fasterxml.jackson.core.JsonParseException",
"message": "Unrecognized token 'eyJhbGciOiJIUzI1NiJ9': was expecting ('true', 'false' or 'null') at [Source: eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsImV4cCI6MTUyNzUyNzY3OCwicm9sZXMiOlt7ImF1dGhvcml0eSI6IkFETUlOIn1dfQ.VibLFbRhNapwK2lw8pAFBvayFTI6CUY1tVNmVHPwBSE; line: 1, column: 21]",
"path": "/login"
}
我唯一清楚的是错误来自这条线:
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonJwt = objectMapper.readTree(jwt);
((ObjectNode)jsonJwt).put("userId", id);
response.addHeader(SecurityConstants.HEADER_STRING,SecurityConstants.TOKEN_PREFIX+objectMapper.writeValueAsString(jsonJwt));
我试图改变如何将JsonNode转换为字符串但没有结果的方式。
PS:我在获取经过身份验证的用户的ID方面没有问题。
有什么想法吗?
编辑
这是SecurityConfig.java:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(bCryptPasswordEncoder);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.authorizeRequests().antMatchers("/login/**").permitAll();
http.authorizeRequests().antMatchers(HttpMethod.GET,"/ListProjects/**").hasAuthority("ADMIN");
http.authorizeRequests().anyRequest().authenticated()
.and()
.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint());
http.authorizeRequests().antMatchers(HttpMethod.OPTIONS, "/**").permitAll(); //allow CORS option calls
// http.addFilter(new JWTAuthenticationFilter(authenticationManager()));
http.addFilter(jwtAuthenticationFilter());
http.addFilterBefore(new JWTAutorizationFilter(), UsernamePasswordAuthenticationFilter.class);
}
@Bean
public AuthenticationEntryPoint authenticationEntryPoint() {
return new AuthenticationEntryPoint() {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException, IOException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED,
"Unauthorized: Authentication token was either missing or invalid.");
}
};
}
@Bean
public JWTAuthenticationFilter jwtAuthenticationFilter() throws Exception {
return new JWTAuthenticationFilter(authenticationManager());
}
答案 0 :(得分:1)
您需要创建自己的UserTokenEnhancer来实现TokenEnhancer接口。
public class UserTokenEnhancer implements TokenEnhancer {
@Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
User user = (User) authentication.getPrincipal();
final Map<String, Object> enhancerInfo = new HashMap<>();
enhancerInfo.put("userInfo", "some_user_info");
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(enhancerInfo);
return accessToken;
}
}
之后,您需要在AuthServerConfig中添加以下代码,该代码扩展了AuthorizationServerConfigurerAdapter
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
// ...
.tokenEnhancer(tokenEnhancer());
}
@Bean
public TokenEnhancer tokenEnhancer() {
return new UserTokenEnhancer();
}
}
这就是全部。