我已经创建了一个REST,它需要使用JWT进行身份验证。
我的实现非常类似于在https://auth0.com/blog/securing-spring-boot-with-jwts/上找到的代码
当我试图返回当前用户时,我总是收到一个null返回。
我的代码:
Websecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests()
// login
.antMatchers(HttpMethod.POST, "/login")
.permitAll()
.anyRequest()
.authenticated()
.and()
.addFilterBefore(new JWTLoginFilter(
"/login", authenticationManager(), logService), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(new JWTAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}JWTAuthenticationFilter
public class JWTAuthenticationFilter extends GenericFilterBean {
@Override
public void doFilter(
ServletRequest req,
ServletResponse res,
FilterChain filterChain) throws IOException, ServletException {
Authentication authentication = TokenAuthenticationService.getAuthentication((HttpServletRequest)req);
SecurityContextHolder.getContext().setAuthentication(authentication);
filterChain.doFilter(req, res);
}
}我没有包含JWT身份验证的所有代码,因为JWT工作正常,用户访问也很好。我认为问题在于过滤器或某些配置。
然后,我使用以下代码(方法4在facade上)创建了一个service或controller上的当前用户:
public Authentication getAuthentication() {
return SecurityContextHolder.getContext().getAuthentication();
}但这不管用。- SecurityContextHolder.getContext()回答org.springframework.security.core.context.SecurityContextImpl@ffffffff: Null authentication。- SecurityContextHolder.getContext().getAuthentication()返回null对象。
更新(和解决方案)
在我的控制器中,如果我使用以下代码:
SecurityContext context = SecurityContextHolder.getContext();
Authentication authentication = context.getAuthentication();我可以获得当前用户,但是,在我的服务中,完全相同的代码不能工作。但是,我记得SecurityContext在另一个线程上“丢失”了(源代码:https://docs.spring.io/spring-security/site/docs/current/reference/html/concurrency.html),我的服务是异步的。
@Async
public CompletableFuture<Optional<ViewUserDto>> findByLogin(String login) throws InterruptedException {
...
}因此,使用这里找到的代码:https://stackoverflow.com/a/40347437/4794469,一切都正常工作。我不知道这是否会给我的代码带来任何副作用(所有单元测试都成功了)
发布于 2017-09-04 22:13:50
我在一个具有类似于您的授权流程的应用程序中工作过:
WebSecurityConfigurerAdapter
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private AuthenticationProvider provider;
@Autowired
private TokenAuthenticationService tokenService;
@Override
protected void configure(AuthenticationManagerBuilder builder) throws Exception {
builder.authenticationProvider(provider);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin().disable();
http.csrf().disable();
http.authorizeRequests().antMatchers(HttpMethod.POST, "/v1/users", "/v1/oauth/token").permitAll()
.anyRequest().authenticated()
.and()
.addFilterBefore(new OAuthTokenFilter("/v1/oauth/token", authenticationManager(), tokenService), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(new AuthorizationFilter(tokenService), UsernamePasswordAuthenticationFilter.class);
}
}AbstractAuthenticationProcessingFilter
public class OAuthTokenFilter extends AbstractAuthenticationProcessingFilter {
private final ObjectMapper MAPPER = new ObjectMapper();
private TokenAuthenticationService service;
public OAuthTokenFilter(String url, AuthenticationManager manager, TokenAuthenticationService service) {
super(new AntPathRequestMatcher(url));
setAuthenticationManager(manager);
this.service = service;
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException, IOException, ServletException {
Login login = MAPPER.readValue(request.getInputStream(), Login.class);
UsernamePasswordAuthenticationToken token =
new UsernamePasswordAuthenticationToken(login.getUsername(), login, Arrays.asList());
return getAuthenticationManager().authenticate(token);
}
@Override
protected void successfulAuthentication(
HttpServletRequest request,
HttpServletResponse response,
FilterChain chain,
Authentication authentication) throws IOException, ServletException {
User credentials = (User) authentication.getPrincipal();
String token = service.jwt(credentials);
String json = MAPPER.writeValueAsString(new AuthorizationToken(token, "Bearer"));
response.addHeader("Content-Type", "application/json");
response.getWriter().write(json);
response.flushBuffer();
}
}GenericFilterBean
public class AuthorizationFilter extends GenericFilterBean {
private TokenAuthenticationService service;
public AuthorizationFilter(TokenAuthenticationService service) {
this.service = service;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
Authentication authentication = service.getAuthentication((HttpServletRequest)request);
SecurityContextHolder.getContext().setAuthentication(authentication);
chain.doFilter(request, response);
}
}TokenAuthenticationService
@Service
public class TokenAuthenticationService {
public static final String JWT_SECRET_ENV = "JWT_SECRET";
public static final String ISSUER = "my issuer";
public static final String ROLE_CLAIM = "role";
public static final String THIRDY_PARTY_ID_CLAIM = "thirdy_party_id";
public static final String TOKEN_PREFIX = "Bearer";
public static final String HEADER = "Authorization";
@Autowired
private Environment environment;
public Authentication getAuthentication(HttpServletRequest request) {
String token = request.getHeader(HEADER);
String secret = environment.getProperty(JWT_SECRET_ENV);
if (token != null) {
try {
String bearer = token.replace(TOKEN_PREFIX, "").trim();
Algorithm algorithm = Algorithm.HMAC256(secret);
JWTVerifier verifier = JWT.require(algorithm)
.withIssuer(ISSUER)
.build();
DecodedJWT jwt = verifier.verify(bearer);
User user = new User();
user.setId(jwt.getSubject());
user.setThirdPartyId(jwt.getClaim(THIRDY_PARTY_ID_CLAIM).asString());
user.setRole(jwt.getClaim(ROLE_CLAIM).asString());
List<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList(user.getRole());
return new UsernamePasswordAuthenticationToken(user, null, authorities);
} catch (Exception e){
e.printStackTrace(System.out);
}
}
return null;
}
}然后,控制器:
@RestController
public class UserController {
@ResponseBody
@GetMapping("/v1/users/{id}")
@PreAuthorize("hasAuthority('USER')")
public User get(@PathVariable("id") String id, Authentication authentication) {
User user = (User) authentication.getPrincipal();
return user;
}
}发布于 2017-09-04 20:08:25
当我在我的web应用程序上启用JWT时,我也遇到了类似的问题。您需要:"Java密码扩展(JCE)无限强管辖权策略文件“。
http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html
https://stackoverflow.com/questions/46043408
复制相似问题