security

package com.xinsixian.caiyi.config;

import com.xinsixian.caiyi.JWTAuthenticationEntryPoint;
import com.xinsixian.caiyi.filter.JWTAuthenticationFilter;
import com.xinsixian.caiyi.filter.JWTAuthorizationFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

  //  @Autowired
 //   @Qualifier("userDetailsServiceImpl")
  ///  private UserDetailsService userDetailsService;

  /*  @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
    }*/

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and().csrf().disable()
                .authorizeRequests()
                // 測試用資源,需要驗證了的用戶才能訪問
                .antMatchers("/user/updateUser/**").authenticated()
                .antMatchers("/article/likeArticle/**").authenticated()
                .antMatchers("/article/likeComment/**").authenticated()
                .antMatchers("/article/comment/**").authenticated()
                .antMatchers("/article/delComment/**").authenticated()
                .antMatchers("/sunticketLikeComment/comment/**").authenticated()
                .antMatchers("/sunticketLikeComment/delComment/**").authenticated()
                .antMatchers("/sunticketLikeComment/likeComment/**").authenticated()
                .antMatchers("/sunticketLikeComment/likeSunticket/**").authenticated()
                .antMatchers("/subFans/**").authenticated()
                .antMatchers("/sunticket/sunticket/**").authenticated()
                .antMatchers("/sunticket/delSunticket/**").authenticated()
                //.antMatchers("/cos/**").authenticated()
                .antMatchers("/WxPay/buyColorC/**").authenticated()
                .antMatchers("/WxPay/withDraw/**").authenticated()
                .antMatchers("/find/publishArticle/**").authenticated()
                .antMatchers("/find/articleApprove/**").authenticated()
                .antMatchers("/find/myBuyArticle/**").authenticated()
                .antMatchers("/find/buyArticle/**").authenticated()
                .antMatchers("/message/queryMessageList").authenticated()
                .antMatchers("/message/countUnreadMessage").authenticated()

                // 其他都放行了
                .antMatchers("/user/wxLogin").permitAll()

                .antMatchers("/configuration/ui", "/swagger-resources", "/configuration/security", "/swagger-ui.html",
                        "/webjars/**","/swagger-resources/configuration/ui","/swagge‌​r-ui.html").permitAll()
                /*.antMatchers("/configuration/ui", "/swagger-resources", "/configuration/security", "/swagger-ui.html",
                      "/webjars/**","/swagger-resources/configuration/ui","/swagge‌​r-ui.html").permitAll()*/
                .and()
                .addFilter(new JWTAuthenticationFilter(authenticationManager()))
                .addFilter(new JWTAuthorizationFilter(authenticationManager()))
                // 不需要session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .exceptionHandling().authenticationEntryPoint(new JWTAuthenticationEntryPoint());
    }

    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
        return source;
    }
}

 

 

filter

package com.xinsixian.caiyi.filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.xinsixian.caiyi.util.token.JwtTokenUtils;
import io.jsonwebtoken.MalformedJwtException;
import org.apache.log4j.Logger;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

public class JWTAuthorizationFilter extends BasicAuthenticationFilter {
    private Logger log = Logger.getLogger(getClass());

    public JWTAuthorizationFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain chain) throws IOException, ServletException {
        Object obj = request.getAttribute("userId");
        if (obj != null) {
            Long userId = Long.parseLong((String)obj);
            log.error("userId == " + userId + " 的用戶被外部強制注入,Ip ==" + request.getLocalAddr());
            response.addHeader("err", "not permit ask");
            return ;
           // throw new AccessDeniedException("userId == " + userId + " 的用戶被外部強制注入");
        }
        String tokenHeader = request.getHeader(JwtTokenUtils.TOKEN_HEADER);
        // 如果請求頭中沒有accessToken信息則直接放行了
        if (tokenHeader == null || !tokenHeader.startsWith(JwtTokenUtils.TOKEN_PREFIX)) {
            chain.doFilter(request, response);//接着走security
            return;
        }
        StringBuilder userIdStr = new StringBuilder("");
     //   try {
            // 如果請求頭中有token,則進行解析,並且設置認證信息
            SecurityContextHolder.getContext().setAuthentication(getAuthentication(tokenHeader, userIdStr));//暫不需要權限驗
            //  getAuthentication(tokenHeader, userId);//簽名認證,一次就好,避免多次認證耗時
            request.setAttribute("userId", userIdStr);
            super.doFilterInternal(request, response, chain);
     /*   } catch (Exception e) {
            e.printStackTrace();
            Map<String, Object> map = new HashMap<>();
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/json; charset=utf-8");
            map.put("code", 401);
            map.put("msg", e.getMessage());
            response.getWriter().write(new ObjectMapper().writeValueAsString(map));
        }*/
    }

    // 這裏從token中獲取用戶信息並新建一個token
    private UsernamePasswordAuthenticationToken getAuthentication(String tokenHeader, StringBuilder userIdStr) {
        String token = tokenHeader.replace(JwtTokenUtils.TOKEN_PREFIX, "");
        userIdStr.append(JwtTokenUtils.getUserId(token).toString());
     //   String role = JwtTokenUtils.getUserRole(token);
        if (!userIdStr.equals("")){
            ///< 此處爲權限驗證的了,微信端暫時可以忽略
            return new UsernamePasswordAuthenticationToken("test", null,
                    Collections.singleton(new SimpleGrantedAuthority("test"))
            );
        }
        return null;
    }
}

 

filter

 

package com.xinsixian.caiyi.filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;

/**
 * 不用這麼偷懶, 次類暫時用不到
 */
public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    private ThreadLocal<Integer> rememberMe = new ThreadLocal<>();
    private AuthenticationManager authenticationManager;

    public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
        super.setFilterProcessesUrl("/auth/login");
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request,
                                                HttpServletResponse response) throws AuthenticationException {

        // 從輸入流中獲取到登錄的信息
   /*     try {
            LoginUser loginUser = new ObjectMapper().readValue(request.getInputStream(), LoginUser.class);
            rememberMe.set(loginUser.getRememberMe());
            return authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(loginUser.getUsername(), loginUser.getPassword(), new ArrayList<>())
            );
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }*/
        return null;
    }

    // 成功驗證後調用的方法
    // 如果驗證成功,就生成token並返回
    @Override
    protected void successfulAuthentication(HttpServletRequest request,
                                            HttpServletResponse response,
                                            FilterChain chain,
                                            Authentication authResult) throws IOException, ServletException {

     /*   JwtUser jwtUser = (JwtUser) authResult.getPrincipal();
        System.out.println("jwtUser:" + jwtUser.toString());
        boolean isRemember = rememberMe.get() == 1;

        String role = "";
        Collection<? extends GrantedAuthority> authorities = jwtUser.getAuthorities();
        for (GrantedAuthority authority : authorities){
            role = authority.getAuthority();
        }

        String token = JwtTokenUtils.createToken(jwtUser.getUsername(), role, isRemember);
//        String token = JwtTokenUtils.createToken(jwtUser.getUsername(), false);
        // 返回創建成功的token
        // 但是這裏創建的token只是單純的token
        // 按照jwt的規定,最後請求的時候應該是 `Bearer token`
        response.setHeader("token", JwtTokenUtils.TOKEN_PREFIX + token);*/
    }

    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
        response.getWriter().write("authentication failed, reason: " + failed.getMessage());
    }
}

 

異常處理

package com.xinsixian.caiyi;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class JWTAuthenticationEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request,
                         HttpServletResponse response,
                         AuthenticationException authException) throws IOException, ServletException {

        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        response.setStatus(HttpServletResponse.SC_FORBIDDEN);
        //String reason = "AccessToken校驗失敗異常捕獲:"+authException.getMessage();
        //String jsonStr = "{code:" + 401 + ", msg:" + reason + "}";
        // response.getWriter().write(new ObjectMapper().writeValueAsString(reason));
        //response.getWriter().write(new ObjectMapper().writeValueAsString(jsonStr));
        Map<String, Object> map = new HashMap<>();
        map.put("code", 401);
        map.put("msg", authException.getMessage() + "need accessToken");
        response.getWriter().write(new ObjectMapper().writeValueAsString(map));
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章