我需要创建一个WebSecurityConfig来处理过滤器。我希望每个请求都传递给过滤器,但在路径中具有“身份验证”的请求除外。这就是我想要做的:
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.antMatcher("/**").addFilterBefore(new AuthenticationFilter(TokenTypeEnum.ACCESS),UsernamePasswordAuthenticationFilter.class).authorizeRequests().anyRequest().authenticated();
httpSecurity.antMatcher("**/authenticate").authorizeRequests().anyRequest().permitAll();
}
}
以这种方式,每个请求都变为开放的问题。如果更改行的顺序,则会过滤每个请求。
答案 0 :(得分:0)
您需要更改authorizeRequests()
的位置,并像这样放置addFilterBefore
:
WebSecurityConfig :
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Resource(name = "userService")
private UserDetailsService userDetailsService;
@Autowired
private JwtAuthenticationEntryPoint unauthorizedHandler;
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Autowired
public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(encoder());
}
@Bean
public JwtAuthenticationFilter authenticationTokenFilterBean() throws Exception {
return new JwtAuthenticationFilter();
}
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.cors().and().csrf().disable().authorizeRequests()
.antMatchers("**/authenticate").permitAll()
.antMatchers("/**").authenticated();
httpSecurity.addFilterBefore(authenticationTokenFilterBean(),UsernamePasswordAuthenticationFilter.class);
httpSecurity.exceptionHandling().authenticationEntryPoint(unauthorizedHandler)
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
@Bean
public BCryptPasswordEncoder encoder(){
return new BCryptPasswordEncoder();
}
}
如果您使用的是 jwt ,则可以为未经身份验证的用户实施规则:
JwtAuthenticatioFilter :
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Autowired
AuthenticationService authenticationService;
public static final String TOKEN_PREFIX = "Bearer ";
public static final String HEADER_STRING = "Authorization";
@Override
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws IOException, ServletException {
String header = req.getHeader(HEADER_STRING);
String username = null;
String authToken = null;
if (header != null && header.startsWith(TOKEN_PREFIX)) {
authToken = header.replace(TOKEN_PREFIX,"");
try {
username = jwtTokenUtil.getUsernameFromToken(authToken);
} catch (IllegalArgumentException e) {
logger.error("an error occured during getting username from token", e);
} catch (ExpiredJwtException e) {
logger.warn("the token is expired and not valid anymore", e);
} catch(SignatureException e){
logger.error("Authentication Failed. Username or Password not valid.");
}
} else {
logger.warn("couldn't find bearer string, will ignore the header");
}
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
authenticationService.authenticate(req, username, authToken);
}
chain.doFilter(req, res);
}
}
JwtTokenUtil :
@Component
public class JwtTokenUtil implements Serializable {
public static final long ACCESS_TOKEN_VALIDITY_SECONDS = 5*60*60;
public static final String SIGNING_KEY = "stack-overflow";
private static final long serialVersionUID = -8713473373534700606L;
public String getUsernameFromToken(String token) {
return getClaimFromToken(token, Claims::getSubject);
}
public Date getExpirationDateFromToken(String token) {
return getClaimFromToken(token, Claims::getExpiration);
}
public <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
final Claims claims = getAllClaimsFromToken(token);
return claimsResolver.apply(claims);
}
private Claims getAllClaimsFromToken(String token) {
return Jwts.parser()
.setSigningKey(SIGNING_KEY)
.parseClaimsJws(token)
.getBody();
}
private Boolean isTokenExpired(String token) {
final Date expiration = getExpirationDateFromToken(token);
return expiration.before(new Date());
}
public String generateToken(User user) {
return doGenerateToken(user.getUsername());
}
private String doGenerateToken(String subject) {
Claims claims = Jwts.claims().setSubject(subject);
claims.put("scopes", Arrays.asList(new SimpleGrantedAuthority("ROLE_ADMIN")));
return Jwts.builder()
.setClaims(claims)
.setIssuer("http://stack.com")
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + ACCESS_TOKEN_VALIDITY_SECONDS*1000))
.signWith(SignatureAlgorithm.HS256, SIGNING_KEY)
.compact();
}
public Boolean validateToken(String token, UserDetails userDetails) {
final String username = getUsernameFromToken(token);
return (
username.equals(userDetails.getUsername())
&& !isTokenExpired(token));
}
}
AuthenticationService :
@Service(value = "authenticationService")
public class AuthenticationService {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Autowired
private UserService userService;
@Autowired
private AuthenticationManager authenticationManager;
public String autenticate(Login login) throws ParseException{
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(login.getUsername(), login.getPassword()));
User user = userService.findByUsername(login.getUsername());
String token = jwtTokenUtil.generateToken(user);
return token;
}
}
AuthToken :
public class AuthToken {
private String token;
private String username;
public AuthToken(){
}
public AuthToken(String token, String username){
this.token = token;
this.username = username;
}
public AuthToken(String token){
this.token = token;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
身份验证终结点:
@CrossOrigin(origins = "*", maxAge = 3600)
@RestController
@RequestMapping("/auth")
public class AuthenticationController {
@Autowired
private AuthenticationService authenticationService;
@RequestMapping(value = "/generate-token", method = RequestMethod.POST)
public AuthToken register(@RequestBody Login login) throws AuthenticationException
{
try {
String token = authenticationService.autenticate(login);
return new AuthToken(token, login.getUsername());
} catch (ParseException e) {
return null;
}
}
}
UserService :
@Service(value = "userService")
public class UserService implements UserDetailsService
{
@Autowired
private UserRepo userRepo;
@Autowired
private BCryptPasswordEncoder bcryptEncoder;
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Optional<User> user = userRepo.findByUsername(username);
if(user.isPresent() == false){
throw new UsernameNotFoundException("Invalid username or password.");
}
return new org.springframework.security.core.userdetails.User(user.get().getUsername(), user.get().getPassword(), true, true, true, true, null);
}
public List<User> findAll() {
List<User> list = new ArrayList<>();
Iterator<User> i = userRepo.findAll().iterator();
i.forEachRemaining(block -> {
User next = i.next();
list.add(next);
}
);
return list;
}
public User findByUsername(String username) throws ParseException {
Optional<User> optionalUser = userRepo.findByUsername(username);
return optionalUser.isPresent() ? optionalUser.get() : null;
}
public User findById(String id) {
Optional<User> optionalUser = userRepo.findById(id);
return optionalUser.isPresent() ? optionalUser.get() : null;
}
}
UserRepository :
@Repository
public interface UserRepo extends CrudRepository<User, String> {
User findByUsername(String username);
}
您可以使用失眠症进行测试: