春季:通过JWT对用户进行一次身份验证,并允许其余会话访问

时间:2020-02-09 13:53:11

标签: spring session jwt

我正在使用Spring boot并试图创建一个接受JWT并验证用户身份的页面。我已经使用自定义的OncePerRequestFilter成功完成了此操作。该解决方案要求用户每次都提供jwt。但是现在我希望用户使用jwt进行一次身份验证,并且能够在不为会话的其余部分提供JWT的情况下访问受保护的资源。我现在该怎么办?

使用以下代码,因为在WebSecurityConfigurerAdapter中将sessionCreation模式设置为STATELESS时,如果不提供jwt,我们将获得http 403(未经授权的访问)。 另一方面,删除了这一行:

fread()

我发送一次提供jwt的请求。之后,我发送不带jwt的请求,这一次我没有被拒绝访问。我收到http 500内部服务器错误。

堆栈跟踪:

library( data.table )
data.table::fread('Month/Year, "Index"
"Feb.2019","125"
"Mar.2019","127"
"April.2019","130" ')

#    Month/Year Index
# 1:   Feb.2019   125
# 2:   Mar.2019   127
# 3: April.2019   130

OncePerRequestFilter

      .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)

使用jwt对用户进行身份验证的过滤器:

java.lang.NullPointerException: null
    at jwt.JwtTokenVerifier.doFilterInternal(JwtTokenVerifier.java:43) ~[classes/:na]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200) ~[spring-security-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116) ~[spring-security-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
    at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:92) ~[spring-security-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:77) ~[spring-security-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) ~[spring-security-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) ~[spring-security-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215) ~[spring-security-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178) ~[spring-security-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358) ~[spring-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271) ~[spring-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.27.jar:9.0.27]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.27.jar:9.0.27]
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.27.jar:9.0.27]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.27.jar:9.0.27]
    at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.27.jar:9.0.27]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.27.jar:9.0.27]
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.27.jar:9.0.27]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.27.jar:9.0.27]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) ~[tomcat-embed-core-9.0.27.jar:9.0.27]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-9.0.27.jar:9.0.27]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:526) [tomcat-embed-core-9.0.27.jar:9.0.27]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) [tomcat-embed-core-9.0.27.jar:9.0.27]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.27.jar:9.0.27]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) [tomcat-embed-core-9.0.27.jar:9.0.27]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) [tomcat-embed-core-9.0.27.jar:9.0.27]
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408) [tomcat-embed-core-9.0.27.jar:9.0.27]
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-9.0.27.jar:9.0.27]
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861) [tomcat-embed-core-9.0.27.jar:9.0.27]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1579) [tomcat-embed-core-9.0.27.jar:9.0.27]
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.27.jar:9.0.27]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) [na:1.8.0_231]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) [na:1.8.0_231]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.27.jar:9.0.27]
    at java.lang.Thread.run(Unknown Source) [na:1.8.0_231]

我们在网络安全性中添加了过滤器:

public class JwtTokenVerifier extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        String token = "";
        try {
            token = request.getHeader("Authorization");
        } catch (Exception e) {
        }

        if (token != "")
            if (token.isEmpty() || token == null || !token.startsWith("Bearer ")) {

                filterChain.doFilter(request, response);
                return;
            }

        try {
            token = token.replace("Bearer ", "");
            Algorithm alg = Algorithm.HMAC512("fStrongPassWordfStrongPassWordfStrongPassWord");
            JWTVerifier verifier = JWT.require(alg).withIssuer("auth0").build(); // Reusable verifier instance
            DecodedJWT jwt = verifier.verify(token);

            String username = jwt.getSubject();
            Claim c = jwt.getClaim("auths");
            String[] auths = c.asArray(String.class);

            Set<GrantedAuthority> ga = new HashSet<>();

            for (int i = 0; i < auths.length; i++) {
                ga.add(new SimpleGrantedAuthority(auths[i]));
            }

            Authentication authn = new UsernamePasswordAuthenticationToken(username, null, ga);
            // isAuthenticated(

            SecurityContext sc = SecurityContextHolder.getContext();
            sc.setAuthentication(authn);
//          SecurityContextHolder.getContext().setAuthentication(authn);
            HttpSession session = request.getSession(true);
            session.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, sc);

        } catch (JWTVerificationException exception) {
            throw new ServletException(String.format("invalid token supplied:\n%s", token));

        }

        filterChain.doFilter(request, response);

    }

}

1 个答案:

答案 0 :(得分:0)

我在回答自己的问题。删除我提到的行足以迫使spring在其余的会话中使用户保持身份验证。显然,默认情况下,SessionCreationPolicy为IF_REQUIRED。这与在WebSecurityConfigurerAdapter中使用以下代码相同:

.sessionManagement()。sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)

问题是我解决了这样的空指针异常:

public class JwtTokenVerifier extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        String token = "";
        try {
//          token = request.getHeader("Authorization");
            token = request.getParameter("authorization");
            if (token == "" || token==null) {
                filterChain.doFilter(request, response);
                return;
            }
        } catch (Exception e) {
        }

        if (token.isEmpty() || token == null || !token.startsWith("Bearer")) {

            filterChain.doFilter(request, response);
            return;
        }

        try {
            token = token.replace("Bearer", "");
            Algorithm alg = Algorithm.HMAC512("fuckingStrongPassWordfuckingStrongPassWordfuckingStrongPassWord");
            JWTVerifier verifier = JWT.require(alg).withIssuer("auth0").build(); // Reusable verifier instance
            DecodedJWT jwt = verifier.verify(token);

            String username = jwt.getSubject();
            Claim c = jwt.getClaim("auths");
            String[] auths = c.asArray(String.class);

            Set<GrantedAuthority> ga = new HashSet<>();

            for (int i = 0; i < auths.length; i++) {
                ga.add(new SimpleGrantedAuthority(auths[i]));
            }

            Authentication authn = new UsernamePasswordAuthenticationToken(username, null, ga);
            // isAuthenticated(

            SecurityContext sc = SecurityContextHolder.getContext();
            sc.setAuthentication(authn);
//          SecurityContextHolder.getContext().setAuthentication(authn);
//          HttpSession session = request.getSession(true);
//          session.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, sc);

        } catch (JWTVerificationException exception) {
            throw new ServletException(String.format("invalid token supplied:\n%s", token));

        }

        filterChain.doFilter(request, response);

    }

}