我想生成一个带有到期日期的JWT,以便人们无需注册和创建用户即可访问系统。这可能吗?我尝试使用JwtTokenProvider
,但它也需要LoginRequest to work
,而Jwts.builder()
也需要一个用户。
答案 0 :(得分:1)
如果要使用spring安全性,则可以创建安全性配置并扩展WebSecurityConfigurerAdapter。然后重点是自定义提供程序。
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private CustomAuthenticationProvider customAuthenticationProvider;
@Autowired
private JWTConfigurer securityConfigurerAdapter;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
//you can write customAuth provider
auth.authenticationProvider(customAuthenticationProvider);
}
@Override
public void configure(WebSecurity web) throws Exception {
//Some ignore etc.
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint)
.and()
.csrf()
.disable().and()
.headers()
.frameOptions()
.disable()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
//important here
.antMatchers("/api/v1/authentication/**").permitAll()
.anyRequest().authenticated()
.and()
.apply(securityConfigurerAdapter);
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return this.authenticationManager();
}
}
这是Filter类,它扩展了genericFilterBean。此类中的每个请求均受到监控 您将检查该令牌是否正确
我创建令牌TokenProvider类,并依赖JWTFilter,然后使用valideToken方法。
如果令牌已发送但未验证,则抛出异常
如果未发送令牌,则进入超级方法,以便流程继续进行并运行auth.authenticationProvider。 Spring知道要在后台启动customAuthenticationProvider,因为您将其设置为SecurityConfiguration类
@Component
public class JWTFilter extends GenericFilterBean {
private final Logger log = LoggerFactory.getLogger(JWTFilter.class);
@Autowired
private TokenProvider tokenProvider;
@Autowired
private MessageSource msgSource;
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
try {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
//Resolve method is optional what you want to use
String jwt = resolveToken(httpServletRequest);
if (StringUtils.hasText(jwt)) {
//token validation is important becouse of expires date into token
// and you will check expired date
if (this.tokenProvider.validateToken(jwt)) {
String jwtMd5 = DigestUtils.md5Hex(jwt);
MDC.put("jwt",jwtMd5);
Authentication authentication = this.tokenProvider.getAuthentication(jwt);
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
filterChain.doFilter(servletRequest, servletResponse);
}catch(Exception ex){
handleException((HttpServletResponse) servletResponse,ex);
}
}
private String resolveToken(HttpServletRequest request) {
String bearerToken = request.getHeader(JWTConfigurer.AUTHENTICATION_HEADER);
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
String jwt = bearerToken.substring(7, bearerToken.length());
return jwt;
}
String jwt = request.getParameter(JWTConfigurer.AUTHENTICATION_TOKEN);
if (StringUtils.hasText(jwt)) {
return jwt;
}
return null;
}
}
您可以使用此类创建令牌或验证令牌 您可以在创建方法中定义令牌到期的到期日期。
@Component public class TokenProvider {
private final Logger log = LoggerFactory.getLogger(TokenProvider.class);
private static final String AUTHORITIES_KEY = "auth";
private static final String WTS_USER_ID = "wtsUserId";
private static final String CHANNEL_PERMISSIONS = "channelPermissions";
private static final String APP_ROLES = "appRoles";
private String secretKey;
private long tokenValidityInSeconds;
@Autowired private ApplicationProperties applicationProperties;
@PostConstruct public void init() {
this.tokenValidityInSeconds = 1000;
}
public String createToken(Authentication authentication, Boolean rememberMe) { List<String> authorities = authentication.getAuthorities().stream().map(authority -> authority.getAuthority())
.collect(Collectors.toList());
//Token creation format is this
// token will be three part important parts are claims and sign
// claims refers to body to use datas
// sign will use to validation
return Jwts.builder().setSubject(authentication.getName()).claim(AUTHORITIES_KEY, authorities)
.claim(WTS_USER_ID, ((JWTAuthentication) authentication).getWtsUserId())
.claim(CHANNEL_PERMISSIONS, ((JWTAuthentication) authentication).getChannelPermissions())
.claim(APP_ROLES, ((JWTAuthentication) authentication).getAppRoles())
.signWith(SignatureAlgorithm.HS512, secretKey).setExpiration(tokenValidityInSeconds).compact(); }
@SuppressWarnings("unchecked") public Authentication getAuthentication(String token) { Claims claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody();
List<String> list = (List<String>) claims.get(AUTHORITIES_KEY); Collection<? extends GrantedAuthority> authorities = list.stream()
.map(authority -> new SimpleGrantedAuthority(authority)).collect(Collectors.toList()); Integer wtsUserId = (Integer) claims.get(WTS_USER_ID); List<String> appRoles = (List<String>) claims.get(APP_ROLES);
ObjectMapper objectMapper = new ObjectMapper(); List<ChannelPermission> channelPermissions = objectMapper.convertValue(claims.get(CHANNEL_PERMISSIONS),
new TypeReference<List<ChannelPermission>>() {
});
return new JWTAuthentication(token, wtsUserId, claims.getSubject(), authorities, channelPermissions, appRoles); }
public boolean validateToken(String authToken) {
try {
Jwts.parser().setSigningKey(secretKey).parseClaimsJws(authToken);
return true;
} catch (SignatureException e) {
log.info("Invalid JWT signature: " + e.getMessage());
return false;
} } }
这是控制人,匿名人员获得JWT令牌。您可以向新的JWT令牌发出所有请求,并且该JWT的到期日期是因为您在提供程序类中设置了到期日期。
@RequestMapping(value = "/login", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public ApiResponse login(@RequestBody @Validated AuthenticationRequestDTO authenticationRequest) {
Authentication authentication = this.authenticationManager.authenticate(new JWTAuthentication(
RandomUid, RandomPwd, "anonymous"));
SecurityContextHolder.getContext().setAuthentication(authentication);
String token = tokenProvider.createToken(authentication, false);
return new ApiResponse(ApiResponseStatus.SUCCESS, new AuthenticationResponseDTO(token));
}