当前位置:   article > 正文

Spring security 整合JWT 接口权限控制_springsecurity整合jwt实现访问控制

springsecurity整合jwt实现访问控制

流程

jwt登录校验流程
在这里插入图片描述

Spring security

Spring security 配置初始化

@Configuration
public class ApplicationSecurity extends WebSecurityConfigurerAdapter {

    public static final String DONT_AUTHENTICATION_PROFIX = "/comm";
    public static final String DONT_IMAGE_PROFIX = "/image";
    public static final Set<String> PERMIT_ALL_URL = Sets.newHashSet(
            DONT_AUTHENTICATION_PROFIX + "/**",
            DONT_IMAGE_PROFIX + "/**"

    );

    // 用于knife4j
    public static final Set<String> KNIFE4J = Sets.newHashSet(
            "/doc.html/**",
            "/webjars/**",
            "/img.icons/**",
            "/swagger-resources/**",
            "/v2/**"
    );
    private static Logger logger = LoggerFactory.getLogger(ApplicationSecurity.class);

    @Autowired
    private MenuMapper menuMapper;

    @Resource
    private JWTAdminAuthenticationFilter jWTAdminAuthenticationFilter;

    @Resource
    private EntryPointUnauthorizedHandler entryPointUnauthorizedHandler;

    @Resource
    private RestAccessDeniedHandler restAccessDeniedHandler;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
		// 禁止页面嵌套 网站可以使用此功能来避免 点击劫持 攻击
        http.headers().frameOptions().disable();

        initAuth(http); // 初始化权限
		
		// 基于token,所以不需要session
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                .authorizeRequests()
                //添加 接口权限
                .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                .antMatchers(KNIFE4J.toArray(new String[]{})).permitAll()
                .antMatchers(PERMIT_ALL_URL.toArray(new String[]{})).permitAll()
                .anyRequest().authenticated()
                .and().headers().cacheControl();
		// 自定义基于jwt拦截器
        http.addFilterBefore(jWTAdminAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);

		// 自定义异常
        http.exceptionHandling()
        //处理没有认证的访问异常
        .authenticationEntryPoint(entryPointUnauthorizedHandler)
        // 处理没有权限时抛出的异常        
        .accessDeniedHandler(restAccessDeniedHandler);

    }

    /**
     * 初始化系统权限内容
     * @param http
     */
    private void initAuth(HttpSecurity http) {
        List<Menu> list = menuMapper.selectList(null);
        try {
            for (Menu auth : list) {
                String role = auth.getGuid();
                String name = auth.getMenuName();
                String url = auth.getUrl();

                if (StringUtils.isNotBlank(url)) {
                    http.authorizeRequests().antMatchers(url).hasRole(role);
                }

                logger.info("init all Authorities, name={}, role={}, url={}", name, role, url);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84

自定义验证类

@Component
public class JWTAdminAuthenticationFilter extends OncePerRequestFilter {

    private static final Logger log = LoggerFactory.getLogger(JWTAdminAuthenticationFilter.class);

    @Autowired
    private JWTHelperUtil jWTHelperUtil;

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

        // 通过请求地址 判断是否需要进行token验证
        authByPath(request, response);

        chain.doFilter(request, response);
    }

    private void authByPath(HttpServletRequest request, HttpServletResponse response) {

        String path = request.getServletPath();
        String[] pp = path.split("/");
        if (pp.length > 1) {
            path = "/" + pp[1] + "/**";
        }
        // 判断是否knife4
        boolean knife4jFlag = ApplicationSecurity.KNIFE4J.contains(path);

        if (knife4jFlag) {
            return;
        }

		// 判断是否进行权限认证
        boolean authentication = ApplicationSecurity.PERMIT_ALL_URL.contains(path);

        if (!authentication) {
            authentication(request, response);
        }
    }

    private void sendNotPermit(HttpServletResponse response) {
        JSONObject jsonObj = new JSONObject();
        try {
            jsonObj.put("code", ServiceCode.TOKEN_INVALID.code);
            jsonObj.put("msg", ServiceCode.TOKEN_INVALID.msg);
            response.setContentType("application/json;charset=utf-8");
            response.getOutputStream().write(jsonObj.toString().getBytes(StandardCharsets.UTF_8));
        } catch (Exception e1) {
            log.error("error={}", e1.getMessage(), e1);
        }
    }

    private void authentication(HttpServletRequest request, HttpServletResponse response) {

        String authHeader = request.getHeader("Authorization");
        String tokenHead = "Bearer ";
        if (StringUtils.isBlank(authHeader)) {
            sendNotPermit(response);
            return;
        }

        if (authHeader.startsWith(tokenHead)) {
            String authToken = authHeader.substring(tokenHead.length());

            try {
            	// 验证token 
                LoginUser mUserVo = jWTHelperUtil.verifyAdminToken(authToken);
				
				// 把用户信息权限放到spring security 上下文当中
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(mUserVo, null, mUserVo.getAuthorities());
                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(authentication);

            } catch (Exception e) {
                log.error("error={}", e.getMessage(), e);
                sendNotPermit(response);
            }
        }
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81

JWT

JWT配置类

@Component
public class JWTHelperUtil {

	private String JWT_SECRET = "wx_app_api_099888";
	private int expires_secs = 60 * 60 * 24 * 7;
	private static final String USER_INFO_KEY = "userInfo";

	@Resource
	private DataCache dataCacheDao;

	/**
	 * 生成token 设置: # 过期时间 # 用户标识 #
	 * 
	 * @param
	 * @return
	 */
	public String getToken(Object loginObj) {

		try {
			//HMAC256 加密
			Algorithm algorithm = Algorithm.HMAC256(JWT_SECRET);
			
			// 添加过期时间
			Calendar expiresAt = Calendar.getInstance();
			expiresAt.add(Calendar.SECOND, expires_secs);
			String userStr = new ObjectMapper().writeValueAsString(loginObj);
			// 生成token
			String token = JWT.create().withClaim(USER_INFO_KEY, userStr).withExpiresAt(expiresAt.getTime()).sign(algorithm);

			return token;
		} catch (JWTVerificationException | JsonProcessingException exception) {
			throw new ServiceBusinessException(ServiceCode.GEN_JWT_TOKEN_FAIL, exception.getMessage());
		}
	}

	// 通过token 获取用户信息
	public String getClaimByToken(String token) {
		// 加密验证
		Algorithm algorithm = Algorithm.HMAC256(JWT_SECRET);
		JWTVerifier verifier = JWT.require(algorithm).build(); 
		// 获取用户信息														
		DecodedJWT jwt = verifier.verify(token);
		String userStr = jwt.getClaim(USER_INFO_KEY).asString();
		return userStr;
	}

	// 验证token
	public LoginUser verifyAdminToken(String token) {

		try {
			// 加密验证
			Algorithm algorithm = Algorithm.HMAC256(JWT_SECRET);
			JWTVerifier verifier = JWT.require(algorithm).build();
			verifier.verify(token);
			// 验证通过 获取该token登录信息 userId auth
			LoginUser adminUser = dataCacheDao.getAdminLoginCacheData(token);

			return adminUser;
		} catch (JWTVerificationException exception) {
			throw new ServiceBusinessException(ServiceCode.TOKEN_INVALID, exception.getMessage());
		} catch (Exception e) {
			e.printStackTrace();
			throw new ServiceBusinessException(ServiceCode.TOKEN_INVALID, e.getMessage());
		}
	}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67

根据token获取用户缓存信息

@Component
public class DataCacheDaoImpl implements DataCache {

	// 短信验证码缓存
	private static final Cache<String, String> SMS_CACHE = CacheBuilder.newBuilder().maximumSize(100000)
			.expireAfterWrite(5, TimeUnit.MINUTES) // 5分钟
			.build();

	//图形验证码缓存
	private static final Cache<String, String> IMAGE_CACHE = CacheBuilder.newBuilder().maximumSize(100000)
			.expireAfterWrite(5, TimeUnit.MINUTES) // 5分钟
			.build();

	// 用户登录
	private static final Cache<String, LoginUser> LOGIN_CACHE = CacheBuilder.newBuilder().maximumSize(100000)
			.expireAfterAccess(30, TimeUnit.MINUTES).build();
	
	@Autowired
	private JWTHelperUtil jWTHelperUtil;

	@Autowired
	private MenuMapper menuMapper;

	@Value("${back.userName}")
	private String SuperBackUserName;

	@Override
	public String getCacheValidCode(String key) {
		return SMS_CACHE.getIfPresent(key);
	}

	@Override
	public void setCacheValidCode(String key, String value) {
		SMS_CACHE.put(key, value);
	}

	@Override
	public String getCacheImageValidCode(String key) {

		if (StringUtils.isBlank(key)) {
			return null;
		}

		return IMAGE_CACHE.getIfPresent(key);
	}

	@Override
	public void setCacheImageValidCode(String key, String value) {
		IMAGE_CACHE.put(key,value);
	}

	@Override
	public void setLoginCacheData(String key, LoginUser value) {
		LOGIN_CACHE.put(key, value);
	}

	@Override
	public String getCacheData(String key) {

		if (StringUtils.isBlank(key)) {
			return null;
		}

		return SMS_CACHE.getIfPresent(key);
	}

	@Override
	public void setCacheData(String key, String value) {
		SMS_CACHE.put(key, value);
	}

	@Override
	public LoginUser getAdminLoginCacheData(String token) {
		LoginUser loginUser = LOGIN_CACHE.getIfPresent(token);
		if(Objects.isNull(loginUser)) {
			String userStr = jWTHelperUtil.getClaimByToken(token);
			JSONObject userObj = JSONObject.parseObject(userStr);
			String type = userObj.getString("type");

			if(Constants.LoginUserType.admin.name().equals(type)) {
				loginUser = loadAdminUserData(token, userObj);
			}/** else if(LoginUserType.api.name().equals(type)) {

			} **/

			loginUser.setType(type);
		}
		return loginUser;
	}

	private LoginUser loadAdminUserData(String token, JSONObject userObj) {
		int userId = userObj.getInteger("id");
		String username = userObj.getString("userName");
		String type = userObj.getString("type");

		// 查询用户所有权限
		Set<GrantedAuthority> authorities = new HashSet<>();
		List<Menu> list;

		if(SuperBackUserName.equalsIgnoreCase(username)) {
			LambdaQueryWrapper<Menu> lambdaQueryWrapper = new LambdaQueryWrapper<>();

			lambdaQueryWrapper.orderBy(true,true,Menu::getSort);
			list = menuMapper.selectList(lambdaQueryWrapper);
		} else {
			list = menuMapper.userAuthority(userId);
		}

		for(Menu menu: list) {
			authorities.add(new SimpleGrantedAuthority(String.format("%s%s",Constants.ROLE_PREFIX,menu.getGuid())));
		}

		LoginUser loginUser = new LoginUser(username, "-", authorities);
		loginUser.setId(userId);
		loginUser.setAuthList(MenuUtils.recursionMenu(0,list));
		loginUser.setType(type);

		setLoginCacheData(token, loginUser);
		return loginUser;
	}

	
	private Set<String> getParentAndSelfAuth(List<Menu> self) {
		List<Menu> all = menuMapper.selectList(null);
		Set<String> returnSet = new HashSet<>();
		Map<String, Menu> map = new HashMap<>();
		for(Menu sa: all) {
			map.put(sa.getGuid(), sa);
		}
		
		for(Menu auth :self) {
			String guid = auth.getGuid();
			returnSet.add(guid);

			Menu sa = map.get(guid);
			while(sa.getParentId()==null) {
				sa = map.get(sa.getParentId());
				returnSet.add(sa.getGuid());
			}
		}
		
		return returnSet;
	}
	
	@Override
	public LoginUser getApiLoginCacheData(String token) {
		LoginUser loginUser = LOGIN_CACHE.getIfPresent(token);
		return loginUser;
	}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151

菜单工具类

public class MenuUtils {

    //递归排序菜单及子菜单
    public static List<Menu> recursionMenu(Integer parentId, List<Menu> menuList) {

        List<Menu> list = new ArrayList<>();
        for (Menu menu : menuList) {
            Integer dataParentId = menu.getParentId();
            if (ObjectUtils.equals(parentId,dataParentId)) {
                List<Menu> menus = recursionMenu(menu.getId(), menuList);
                menu.setChild(menus);
                list.add(menu);
            }
        }

        return list;
    }

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

通过Spring security提取登录用户信息

public class CommUtils {

	public static String randomUUID() {
		return UUID.randomUUID().toString().replace("-", "").toLowerCase();
	}

	public static String serialId(String prefix) {
		// 32位
		String dStr = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date()); // 17
		String uuid = prefix + randomUUID(); // 18
		return uuid.substring(0, 15) + dStr;
	}
	
	public static String getClientIp() {
		HttpServletRequest request = getRequest();
		String ip = request.getHeader("x-forwarded-for");
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
		}
		return ip;
	}
	
	public static String md5Encode(String password) {
        MessageDigest md5 = null;
        try {
            md5 = MessageDigest.getInstance("MD5");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        char[] charArray = password.toCharArray();
        byte[] byteArray = new byte[charArray.length];

        for (int i = 0; i < charArray.length; i++)
            byteArray[i] = (byte) charArray[i];
        byte[] md5Bytes = md5.digest(byteArray);
        StringBuilder hexValue = new StringBuilder();
        for (int i = 0; i < md5Bytes.length; i++) {
            int val = ((int) md5Bytes[i]) & 0xff;
            if (val < 16) {
                hexValue.append("0");
            }

            hexValue.append(Integer.toHexString(val));
        }
        return hexValue.toString();
    }

	// 获取用户登录信息
	public static LoginUser getLoginUserInfo() {
		SecurityContext securityContext = SecurityContextHolder.getContext();
		Authentication authentication = securityContext.getAuthentication();
		if (authentication == null) {
			return null;
		}
		Object principal = authentication.getPrincipal();
		if (principal == null || principal instanceof String) {
			return null;
		}
		return (LoginUser) principal;
	}
	
	public static HttpServletRequest getRequest() {
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
		return request;
	}
	
	public static HttpServletResponse getResponse() {
        HttpServletResponse response=((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        return response;
	}
	
	public static String randomSmsValidCode() {
		Random rand = new Random();
		StringBuilder s = new StringBuilder(6);
		for (int i = 0; i < 6; i++) {
			s.append((int) (rand.nextInt(9)));
		}
		return s.toString();
	}
	
	public static void main(String[] args) {
		System.out.println(md5Encode("123456"));
	}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/546349
推荐阅读
相关标签
  

闽ICP备14008679号