我可以在没有用户的情况下为我的Spring Security应用程序生成JWT吗?

时间:2019-10-23 19:27:24

标签: java spring spring-security jwt

我想生成一个带有到期日期的JWT,以便人们无需注册和创建用户即可访问系统。这可能吗?我尝试使用JwtTokenProvider,但它也需要LoginRequest to work,而Jwts.builder()也需要一个用户。

1 个答案:

答案 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));
}
相关问题