【问题标题】:Can I generate a JWT for my Spring Security app without have a user?我可以在没有用户的情况下为我的 Spring Security 应用程序生成 JWT 吗?
【发布时间】:2019-10-25 14:55:46
【问题描述】:

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

【问题讨论】:

  • 如果任何人都可以获得 JWT,它的价值是什么?......
  • 删除每个人都可以访问的端点的安全性
  • @RobOhRob 有一个用例的可能性,他将创建 JWT 令牌并秘密地与客户共享。在他的情况下,他不想区分客户,即用户。
  • 可以在filter中实现。其中过滤器检查标头并读取授权标头并设置authenticated = true,authorities=只是一个空的arrayList,并且您的所有端点都应该是hasRole,而是使用.antMatchers("/yourUrl/**").authenticated();
  • @PraveenKumarLalasangi 那么他为什么不为他的客户登录呢?......

标签: java spring spring-security jwt


【解决方案1】:

如果你想使用 Spring Security,你可以创建安全配置并扩展 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();
    }

}

这是扩展 genericFilterBean 的过滤器类。在这个类中监控每个请求 你会检查它是正确的令牌

我创建令牌 TokenProvider 类并依赖于 JWTFilter 然后使用 valideToken 方法。

如果令牌被发送但未验证,则抛出异常

如果未发送令牌,则转到 super 方法,以便流程继续并工作 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;
}


}

您可以使用此类创建令牌或验证令牌 您将令牌过期的过期日期定义到 create 方法中。

@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));
}

【讨论】:

    猜你喜欢
    • 2015-04-13
    • 1970-01-01
    • 1970-01-01
    • 2017-10-09
    • 2017-10-30
    • 2014-07-04
    • 2012-09-14
    • 2011-09-16
    • 1970-01-01
    相关资源
    最近更新 更多