• Spring Security JWT


    首先需要创建2个过滤器. JwtLoginFilter 和 JwtAuthenticationFilter .

    JwtLoginFilter 用来处理用户登录请求.

    JwtAuthenticationFilter 用来处理JwtToken的验证解析.

    /**
     * @author: 阮胜
     * @date: 2018/7/10 8:42
     */
    public class JwtLoginFilter extends AbstractAuthenticationProcessingFilter {
    
        private static final String POST = "POST";
        private AuthenticationSuccessHandler successHandler = new JwtLoginSucessHandler();
        private AuthenticationFailureHandler failureHandler = new JwtLoginFailureHandler();
    
        public JwtLoginFilter(AuthenticationManager authenticationManager) {
            super(new AntPathRequestMatcher("/user/login", "POST"));
            setAuthenticationManager(authenticationManager);
        }
    
    
        @Override
        public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
                throws AuthenticationException, IOException, ServletException {
            if (!request.getMethod().equals(POST)) {
                throw new AuthenticationServiceException(
                        "Authentication method not supported: " + request.getMethod());
            }
    
            String username = request.getParameter("username");
            String password = request.getParameter("password");
    
            if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
    
                PrintWriter writer = response.getWriter();
                writer.write("用户名或者密码为空");
                writer.close();
                return null;
            }
            username = username.trim();
            UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
                    username, password);
            authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
            return this.getAuthenticationManager().authenticate(authRequest);
        }
    
        @Override
        protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
            JwtTokenUtil jwtTokenUtil = new JwtTokenUtil();
            JwtToken jwtToken = new JwtToken(authResult.getName(), authResult.getAuthorities().iterator().next().toString(), jwtTokenUtil.generateExpirationDate());
            String jwtTokenStr = jwtTokenUtil.generateToken(jwtToken);
            response.addHeader("Authorization", jwtTokenStr);
            successHandler.onAuthenticationSuccess(request, response, authResult);
        }
    
        @Override
        protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
            failureHandler.onAuthenticationFailure(request, response, failed);
        }
    
        public void setSuccessHandler(AuthenticationSuccessHandler successHandler) {
            this.successHandler = successHandler;
        }
    
        public void setFailureHandler(AuthenticationFailureHandler failureHandler) {
            this.failureHandler = failureHandler;
        }
    }

    /**
     * @author: 阮胜
     * @date: 2018/7/10 10:44
     */
    public class JwtAuthenticationFilter extends BasicAuthenticationFilter {
        public JwtAuthenticationFilter(AuthenticationManager authenticationManager) {
            super(authenticationManager);
        }
    
        @Autowired
        private JwtTokenUtil jwtTokenUtil;
    
        @Override
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
            String jwtTokenStr = request.getHeader("Authorization");
            if (!StringUtils.isEmpty(jwtTokenStr)) {
                try {
                    if (!jwtTokenUtil.validateToken(jwtTokenStr)) {
                        throw new InvalidJwtTokenException();
                    }
                    JwtToken jwtToken = jwtTokenUtil.parseJwtToken(jwtTokenStr);
                    UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(jwtToken.getUsername(), null
                            , AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_".concat(jwtToken.getRole())));
                    SecurityContextHolder.getContext().setAuthentication(authenticationToken);
                } catch (Exception e) {
                    sendError(response, "无效的Token");
                    return;
                }
            }
            chain.doFilter(request, response);
        }
    
        private void sendError(HttpServletResponse response, String msg) throws IOException {
            response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
            response.setContentType("text/plain;charset=utf-8");
            PrintWriter writer = response.getWriter();
            writer.write(msg);
            writer.close();
        }
    }

    配置类:

    /**
     * @author: 阮胜
     * @date: 2018/7/10 8:33
     */
    @Configuration
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
        private final AccessDeniedHandler accessDeniedHandler;
        private final AuthenticationEntryPoint authenticationEntryPoint;
        private final UserDetailServiceImpl userDetailsService;
    
        public SecurityConfig(AccessDeniedHandler accessDeniedHandler, AuthenticationEntryPoint authenticationEntryPoint, UserDetailServiceImpl userDetailsService) {
            this.accessDeniedHandler = accessDeniedHandler;
            this.authenticationEntryPoint = authenticationEntryPoint;
            this.userDetailsService = userDetailsService;
        }
    
        @Bean
        public PasswordEncoder passwordEncoder() {
            return new DefaultEncoder();
        }
    
        @Bean
        public JwtLoginFilter jwtLoginFilter() throws Exception {
            JwtLoginFilter jwtLoginFilter = new JwtLoginFilter(authenticationManager());
            jwtLoginFilter.setAuthenticationSuccessHandler((request, response, authentication) -> {
                System.out.println("success");
            });
            jwtLoginFilter.setAuthenticationFailureHandler((request, response, exception) -> {
                System.out.println("false");
            });
            return jwtLoginFilter;
        }
    
        @Bean
        public JwtAuthenticationFilter jwtAuthenticationFilter() throws Exception {
            return new JwtAuthenticationFilter(authenticationManager());
        }
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests().antMatchers("/admin", "/admin/info").hasRole("ADMIN")
                    .anyRequest().permitAll()
                    .and().userDetailsService(userDetailsService)
                    //如果已经登录,但没有访问资源的权限,则调用该Handler
                    .exceptionHandling().accessDeniedHandler(accessDeniedHandler)
                    //如果未登录,没有权限则调用该EntryPoint
                    .authenticationEntryPoint(authenticationEntryPoint)
                    // 无状态的Session机制(即Spring不使用HTTPSession),对于所有的请求都做权限校验
                    .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                    //关闭跨域保护
                    .and().csrf().disable();
    
            //把自己写的2个filter加入到过滤器链中
            http.addFilterBefore(jwtLoginFilter(), UsernamePasswordAuthenticationFilter.class)
                    .addFilter(jwtAuthenticationFilter());
        }
    }

    工具类:

    package com.example.springsecurityjwtdemo.util;
    
    import com.example.springsecurityjwtdemo.exception.InvalidJwtTokenException;
    import io.jsonwebtoken.Claims;
    import io.jsonwebtoken.Jwts;
    import io.jsonwebtoken.SignatureAlgorithm;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.stereotype.Component;
    
    import java.io.Serializable;
    import java.util.Date;
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * @author 阮胜
     * @date 2018/7/5 21:21
     */
    @Component
    public class JwtTokenUtil implements Serializable {
    
        private static final long serialVersionUID = -3301605591108950415L;
    
        public static final String USERNAME = "username";
        public static final String ROLE = "role";
        public static final String CREATED_DATE = "createdDate";
        private static final String SECRET = "jwt_secret";
        private static final int EXPIRED_TIME_SECONDS = 60 * 60 * 24 * 7;
    
        public JwtToken parseJwtToken(String token) throws InvalidJwtTokenException {
            Claims claims = obtainClaims(token);
            if (claims == null) {
                throw new InvalidJwtTokenException();
            }
            return new JwtToken(claims.get(USERNAME).toString(), claims.get(ROLE).toString(), claims.get(CREATED_DATE, Date.class));
        }
    
        public String obtainUsername(String token) {
            String username;
            try {
                final Claims claims = obtainClaims(token);
                username = claims.getSubject();
            } catch (Exception e) {
                username = null;
            }
            return username;
        }
    
    
        public Date obtainExpiredDate(String token) {
            Date expiration;
            try {
                final Claims claims = obtainClaims(token);
                expiration = claims.getExpiration();
            } catch (Exception e) {
                expiration = null;
            }
            return expiration;
        }
    
        private Claims obtainClaims(String token) {
            Claims claims;
            try {
                claims = Jwts.parser()
                        .setSigningKey(SECRET)
                        .parseClaimsJws(token)
                        .getBody();
            } catch (Exception e) {
                claims = null;
            }
            return claims;
        }
    
    
        public Date generateExpirationDate() {
            long expired = System.currentTimeMillis() + EXPIRED_TIME_SECONDS * 1000;
            return new Date(expired);
        }
    
        private boolean isTokenExpired(String token) {
            final Date expiration = obtainExpiredDate(token);
            return expiration.after(new Date());
        }
    
        public String generateToken(UserDetails userDetails) {
            return generateToken(
                    new JwtToken(userDetails.getUsername()
                            , userDetails.getAuthorities().iterator().next().toString()
                            , new Date()));
        }
    
        private String generateToken(Map<String, Object> claims) {
            return Jwts.builder()
                    .setClaims(claims)
                    .setExpiration(generateExpirationDate())
                    .signWith(SignatureAlgorithm.HS512, SECRET)
                    .compact();
        }
    
        public String generateToken(JwtToken jwtToken) {
            HashMap<String, Object> tokenMap = new HashMap<>(3);
            tokenMap.put(JwtTokenUtil.USERNAME, jwtToken.getUsername());
            tokenMap.put(JwtTokenUtil.CREATED_DATE, jwtToken.getExpiredDate());
            tokenMap.put(JwtTokenUtil.ROLE, jwtToken.getRole());
            return generateToken(tokenMap);
        }
    
        public boolean validateToken(String token) {
            Date expiredDate = obtainExpiredDate(token);
            return expiredDate != null && expiredDate.after(new Date());
        }
    }
    package com.example.springsecurityjwtdemo.util;
    
    import lombok.Data;
    
    import java.util.Date;
    
    /**
     * @author 阮胜
     * @date 2018/7/5 20:54
     */
    @Data
    public class JwtToken {
        private String username;
        private String role;
        private Date expiredDate;
    
        public JwtToken() {
        }
    
        public JwtToken(String username, String role, Date expiredDate) {
    
            this.username = username;
            this.role = role;
            this.expiredDate = expiredDate;
        }
    }
  • 相关阅读:
    对 HTML 语义化的理解
    cookies,sessionStorage 和 localStorage 的区别
    display:none和visibility:hidden两者的区别
    页面导入样式时,使用link和@import有什么区别
    ES6之let和const
    v-if和v-show 的区别
    解决:Sass Loader has been initialised using an options object that does not ma tch the API schema.
    [转]javaweb学习总结(十四)——JSP原理
    [转]JavaWeb学习总结(十三)——使用Session防止表单重复提交
    [转]JavaWeb学习总结(十二)——Session
  • 原文地址:https://www.cnblogs.com/cearnach/p/9288971.html
Copyright © 2020-2023  润新知