问题描述
我有以下应用程序。
SpringMainApplication.java
@SpringBootApplication
public class SpringMainApplication extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(SpringMainApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(SpringMainApplication.class,args);
}
}
@RestController
class MainController {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private JwtUtil jwtTokenUtil;
@Autowired
private MyUserDetailsService userDetailsService;
@Value("${token.expiration.time}")
private int tokenExpirationTime;
@RequestMapping(value = "/service1/access-token",method = RequestMethod.POST)
public ResponseEntity<?> createAuthenticationToken(@RequestBody AuthenticationRequest authenticationRequest) throws Exception {
try {
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(authenticationRequest.getUsername(),authenticationRequest.getPassword()));
}
catch (BadCredentialsException e) {
throw new Exception("Incorrect password",e);
}
final UserDetails userDetails = userDetailsService
.loadUserByUsername(authenticationRequest.getUsername());
final String jwt = jwtTokenUtil.generateToken(userDetails);
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.set("expiration",String.valueOf(tokenExpirationTime / 1000));
return ResponseEntity.ok().headers(responseHeaders).body(new AuthenticationResponse(jwt));
}
@RequestMapping(value = "/service1/test",consumes = "application/json",method = RequestMethod.GET)
public ResponseEntity<?> checkServerStatus() throws Exception {
// SOME CODE
}
@RequestMapping(value = "/service2/access-token",String.valueOf(tokenExpirationTime / 1000));
return ResponseEntity.ok().headers(responseHeaders).body(new AuthenticationResponse(jwt));
}
@RequestMapping(value = "/service2/test",method = RequestMethod.GET)
public ResponseEntity<?> checkServerStatus() throws Exception {
// SOME CODE
}
@EnableWebSecurity
class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService myUserDetailsService;
@Autowired
private JwtRequestFilter jwtRequestFilter;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(myUserDetailsService);
}
@Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.csrf().disable()
.authorizeRequests().antMatchers("/**/service1/access-token").permitAll().
anyRequest().authenticated().and().
exceptionHandling().and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
httpSecurity.addFilterBefore(jwtRequestFilter,UsernamePasswordAuthenticationFilter.class);
}
}
MyUserDetailsService.java
@Service
public class MyUserDetailsService implements UserDetailsService {
@Value("${username1}")
private String username;
@Value("${password1}")
private String password;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
if (username != null && username.equals(username1)) {
return new User(username,password1,new ArrayList<>());
} else {
throw new UsernameNotFoundException("Username not found: " + username);
}
}
}
JwtRequestFilter.java
@Component
public class JwtRequestFilter extends OncePerRequestFilter {
@Autowired
private MyUserDetailsService userDetailsService;
@Autowired
private JwtUtil jwtUtil;
@Override
protected void doFilterInternal(HttpServletRequest request,HttpServletResponse response,FilterChain chain) throws ServletException,IOException {
final String authorizationHeader = request.getHeader("Authorization");
String username = null;
String jwt = null;
StringBuilder sb = new StringBuilder();
try {
if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
jwt = authorizationHeader.substring(7);
username = jwtUtil.extractUsername(jwt);
}
} catch (UnsupportedJwtException e) {
sb = buildResponseBody(request,e.getMessage());
response.setContentType("application/json;charset=UTF-8");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write(sb.toString());
return;
}
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
if (jwtUtil.validateToken(jwt,userDetails)) {
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(userDetails,null,userDetails.getAuthorities());
usernamePasswordAuthenticationToken
.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
}
}
chain.doFilter(request,response);
}
}
JwtUtil.java
@Service
public class JwtUtil {
@Value("${token.expiration.time}")
private String tokenExpirationTime;
private String SECRET_KEY = "some_secret";
public String extractUsername(String token) {
return extractClaim(token,Claims::getSubject);
}
public Date extractExpiration(String token) {
return extractClaim(token,Claims::getExpiration);
}
public <T> T extractClaim(String token,Function<Claims,T> claimsResolver) {
final Claims claims = extractAllClaims(token);
return claimsResolver.apply(claims);
}
private Claims extractAllClaims(String token) {
return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody();
}
private Boolean isTokenExpired(String token) {
return extractExpiration(token).before(new Date());
}
public String generateToken(UserDetails userDetails) {
Map<String,Object> claims = new HashMap<>();
return createToken(claims,userDetails.getUsername());
}
private String createToken(Map<String,Object> claims,String subject) {
return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + Integer.parseInt(tokenExpirationTime)))
.signWith(SignatureAlgorithm.HS256,SECRET_KEY).compact();
}
public Boolean validateToken(String token,UserDetails userDetails) {
final String username = extractUsername(token);
return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
}
}
我遇到的问题是,如果我通过调用 service1/access-token
生成令牌,我仍然可以使用 jwt 调用 service2/test
,反之亦然。
如何限制用户使用有效的 service1 令牌访问 service2?
我相信我可能需要创建第二个 WebSecurityConfig
类来处理 service2,但我不确定它是如何完成的,因为当我尝试添加一个时,应用程序将无法编译。
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)