@Service
public class CustomUserDetailsServiceImpl implements UserDetailsService {
/**
* 加载用户
*
* @param userName username用户名
* @return CustomUserDetails
* @throws UsernameNotFoundException 找不到用户异常
*/
@Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
if (userName.equals("root")) {
User user = new User(userName, new BCryptPasswordEncoder().encode("123456"), new ArrayList<>());
return new CustomUserDetails(user);
}
throw new UsernameNotFoundException(userName);
}
}
创建jwt相关 --> token过滤器以及匿名用户访问无权限资源时问题
- token过滤器
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
String jwt = resolveToken(request);
if (jwt != null && !"".equals(jwt.trim()) && SecurityContextHolder.getContext().getAuthentication() == null) {
if (JwtTokenUtils.validateToken(jwt)) {
/**
* get auth info
*/
Authentication authentication = JwtTokenUtils.getAuthentication(jwt);
/**
* save user info to securityContext
*/
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
chain.doFilter(request, response);
}
/**
* Get token from header
*/
private String resolveToken(HttpServletRequest request) {
String token = request.getHeader("token");
if (StrUtil.isNotEmpty(token)) {
return token;
}
return null;
}
}
- 匿名用户访问无权限资源时问题
@Component
@Slf4j
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
AuthenticationException e) throws IOException {
log.error("Responding with unauthorized error. Message - {}", e.getMessage());
httpServletResponse.setHeader("content-type", "application/json;charset=UTF-8");
httpServletResponse.setStatus(200);
Result failure = Result.failed(e.getLocalizedMessage());
failure.setCode(-2);
PrintWriter writer = httpServletResponse.getWriter();
writer.print(JSON.toJSONString(failure));
writer.close();
}
}
创建jwt工具类,包含获取token以及token验证
@UtilityClass
@Slf4j
public class JwtTokenUtils {
private static final String AUTHORITIES_KEY = "vvv";
/**
* secret key
*/
private static final String secretKey = "vvv";
/**
* Token validity time(ms)
*/
private static final long tokenValidityInMilliseconds = 1000 * 60 * 30L;
/**
* Create token
*
* @param authentication auth info
* @return token
*/
public String createToken(Authentication authentication) {
/**
* Current time
*/
long now = (new Date()).getTime();
/**
* Validity date
*/
Date validity;
validity = new Date(now + tokenValidityInMilliseconds);
/**
* create token
*/
return Jwts.builder()
.setSubject(authentication.getName())
.claim(AUTHORITIES_KEY, "")
.setExpiration(validity)
.signWith(SignatureAlgorithm.HS256, secretKey)
.compact();
}
/**
* Create token
*
* @param name auth info
* @return token
*/
public String createToken(String name) {
/**
* Current time
*/
long now = (new Date()).getTime();
/**
* Validity date
*/
Date validity;
validity = new Date(now + tokenValidityInMilliseconds);
/**
* create token
*/
return Jwts.builder()
.setSubject(name)
.claim(AUTHORITIES_KEY, "")
.setExpiration(validity)
.signWith(SignatureAlgorithm.HS256, secretKey)
.compact();
}
/**
* Get auth Info
*
* @param token token
* @return auth info
*/
public Authentication getAuthentication(String token) {
/**
* parse the payload of token
*/
Claims claims = Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(token)
.getBody();
List<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList((String) claims.get(AUTHORITIES_KEY));
User principal = new User(claims.getSubject(), "", authorities);
return new UsernamePasswordAuthenticationToken(principal, "", authorities);
}
/**
* validate token
*
* @param token token
* @return whether valid
*/
public boolean validateToken(String token) {
try {
Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token);
return true;
} catch (SignatureException e) {
log.info("Invalid JWT signature.");
log.trace("Invalid JWT signature trace: {}", e);
} catch (MalformedJwtException e) {
log.info("Invalid JWT token.");
log.trace("Invalid JWT token trace: {}", e);
} catch (ExpiredJwtException e) {
log.info("Expired JWT token.");
log.trace("Expired JWT token trace: {}", e);
} catch (UnsupportedJwtException e) {
log.info("Unsupported JWT token.");
log.trace("Unsupported JWT token trace: {}", e);
} catch (IllegalArgumentException e) {
log.info("JWT token compact of handler are invalid.");
log.trace("JWT token compact of handler are invalid trace: {}", e);
}
return false;
}
}
创建配置类WebSecurityConfig,配置和前端对接接口访问权限,以及用户信息
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomUserDetailsServiceImpl userDetailsService;
@Autowired
private JwtAuthenticationEntryPoint unauthorizedHandler;
@Bean(name = BeanIds.AUTHENTICATION_MANAGER)
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/login/*").permitAll()
.anyRequest().authenticated().and()
// custom token authorize exception handler
.exceptionHandling()
.authenticationEntryPoint(unauthorizedHandler).and()
// since we use jwt, session is not necessary
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
// since we use jwt, csrf is not necessary
.csrf().disable();
http.addFilterBefore(new JwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
//关闭自带登录
http.formLogin().disable();
//关闭自带登出
http.logout().disable();
// disable cache
http.headers().cacheControl();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}