@@ -1,11 +1,8 @@ | |||
package com.xkcoding.rbac.security.config; | |||
import com.google.common.collect.Lists; | |||
import lombok.Data; | |||
import org.springframework.boot.context.properties.ConfigurationProperties; | |||
import java.util.List; | |||
/** | |||
* <p> | |||
* 自定义配置 | |||
@@ -25,5 +22,5 @@ public class CustomConfig { | |||
/** | |||
* 不需要拦截的地址 | |||
*/ | |||
private List<String> ignores = Lists.newArrayList(); | |||
private IgnoreConfig ignores; | |||
} |
@@ -0,0 +1,67 @@ | |||
package com.xkcoding.rbac.security.config; | |||
import com.google.common.collect.Lists; | |||
import lombok.Data; | |||
import java.util.List; | |||
/** | |||
* <p> | |||
* 忽略配置 | |||
* </p> | |||
* | |||
* @package: com.xkcoding.rbac.security.config | |||
* @description: 忽略配置 | |||
* @author: yangkai.shen | |||
* @date: Created in 2018-12-17 17:37 | |||
* @copyright: Copyright (c) 2018 | |||
* @version: V1.0 | |||
* @modified: yangkai.shen | |||
*/ | |||
@Data | |||
public class IgnoreConfig { | |||
/** | |||
* 需要忽略的 URL 格式,不考虑请求方法 | |||
*/ | |||
private List<String> pattern = Lists.newArrayList(); | |||
/** | |||
* 需要忽略的 GET 请求 | |||
*/ | |||
private List<String> get = Lists.newArrayList(); | |||
/** | |||
* 需要忽略的 POST 请求 | |||
*/ | |||
private List<String> post = Lists.newArrayList(); | |||
/** | |||
* 需要忽略的 DELETE 请求 | |||
*/ | |||
private List<String> delete = Lists.newArrayList(); | |||
/** | |||
* 需要忽略的 PUT 请求 | |||
*/ | |||
private List<String> put = Lists.newArrayList(); | |||
/** | |||
* 需要忽略的 HEAD 请求 | |||
*/ | |||
private List<String> head = Lists.newArrayList(); | |||
/** | |||
* 需要忽略的 PATCH 请求 | |||
*/ | |||
private List<String> patch = Lists.newArrayList(); | |||
/** | |||
* 需要忽略的 OPTIONS 请求 | |||
*/ | |||
private List<String> options = Lists.newArrayList(); | |||
/** | |||
* 需要忽略的 TRACE 请求 | |||
*/ | |||
private List<String> trace = Lists.newArrayList(); | |||
} |
@@ -1,7 +1,9 @@ | |||
package com.xkcoding.rbac.security.config; | |||
import cn.hutool.core.collection.CollUtil; | |||
import cn.hutool.core.util.ObjectUtil; | |||
import cn.hutool.core.util.StrUtil; | |||
import com.google.common.collect.Sets; | |||
import com.xkcoding.rbac.security.common.Status; | |||
import com.xkcoding.rbac.security.exception.SecurityException; | |||
import com.xkcoding.rbac.security.service.CustomUserDetailsService; | |||
@@ -9,6 +11,7 @@ import com.xkcoding.rbac.security.util.JwtUtil; | |||
import com.xkcoding.rbac.security.util.ResponseUtil; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.springframework.beans.factory.annotation.Autowired; | |||
import org.springframework.http.HttpMethod; | |||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; | |||
import org.springframework.security.core.context.SecurityContextHolder; | |||
import org.springframework.security.core.userdetails.UserDetails; | |||
@@ -22,6 +25,7 @@ import javax.servlet.ServletException; | |||
import javax.servlet.http.HttpServletRequest; | |||
import javax.servlet.http.HttpServletResponse; | |||
import java.io.IOException; | |||
import java.util.Set; | |||
/** | |||
* <p> | |||
@@ -50,14 +54,10 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { | |||
@Override | |||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { | |||
if (CollUtil.isNotEmpty(customConfig.getIgnores())) { | |||
for (String ignore : customConfig.getIgnores()) { | |||
AntPathRequestMatcher matcher = new AntPathRequestMatcher(ignore); | |||
if (matcher.matches(request)) { | |||
filterChain.doFilter(request, response); | |||
return; | |||
} | |||
} | |||
if (checkIgnores(request)) { | |||
filterChain.doFilter(request, response); | |||
return; | |||
} | |||
String jwt = jwtUtil.getJwtFromRequest(request); | |||
@@ -82,4 +82,72 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { | |||
} | |||
/** | |||
* 请求是否不需要进行权限拦截 | |||
* | |||
* @param request 当前请求 | |||
* @return true - 忽略,false - 不忽略 | |||
*/ | |||
private boolean checkIgnores(HttpServletRequest request) { | |||
String method = request.getMethod(); | |||
HttpMethod httpMethod = HttpMethod.resolve(method); | |||
if (ObjectUtil.isNull(httpMethod)) { | |||
httpMethod = HttpMethod.GET; | |||
} | |||
Set<String> ignores = Sets.newHashSet(); | |||
switch (httpMethod) { | |||
case GET: | |||
ignores.addAll(customConfig.getIgnores() | |||
.getGet()); | |||
break; | |||
case PUT: | |||
ignores.addAll(customConfig.getIgnores() | |||
.getPut()); | |||
break; | |||
case HEAD: | |||
ignores.addAll(customConfig.getIgnores() | |||
.getHead()); | |||
break; | |||
case POST: | |||
ignores.addAll(customConfig.getIgnores() | |||
.getPost()); | |||
break; | |||
case PATCH: | |||
ignores.addAll(customConfig.getIgnores() | |||
.getPatch()); | |||
break; | |||
case TRACE: | |||
ignores.addAll(customConfig.getIgnores() | |||
.getTrace()); | |||
break; | |||
case DELETE: | |||
ignores.addAll(customConfig.getIgnores() | |||
.getDelete()); | |||
break; | |||
case OPTIONS: | |||
ignores.addAll(customConfig.getIgnores() | |||
.getOptions()); | |||
break; | |||
default: | |||
break; | |||
} | |||
ignores.addAll(customConfig.getIgnores() | |||
.getPattern()); | |||
if (CollUtil.isNotEmpty(ignores)) { | |||
for (String ignore : ignores) { | |||
AntPathRequestMatcher matcher = new AntPathRequestMatcher(ignore, method); | |||
if (matcher.matches(request)) { | |||
return true; | |||
} | |||
} | |||
} | |||
return false; | |||
} | |||
} |
@@ -1,12 +1,11 @@ | |||
package com.xkcoding.rbac.security.config; | |||
import cn.hutool.core.collection.CollUtil; | |||
import cn.hutool.core.util.ArrayUtil; | |||
import com.xkcoding.rbac.security.service.CustomUserDetailsService; | |||
import org.springframework.beans.factory.annotation.Autowired; | |||
import org.springframework.boot.context.properties.EnableConfigurationProperties; | |||
import org.springframework.context.annotation.Bean; | |||
import org.springframework.context.annotation.Configuration; | |||
import org.springframework.http.HttpMethod; | |||
import org.springframework.security.authentication.AuthenticationManager; | |||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; | |||
import org.springframework.security.config.annotation.web.builders.HttpSecurity; | |||
@@ -81,9 +80,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { | |||
// 认证请求 | |||
.authorizeRequests() | |||
// 放行 /api/auth/** 的所有请求,参见 AuthController | |||
//.antMatchers("/api/auth/**") | |||
//.permitAll() | |||
// 所有请求都需要登录访问 | |||
.anyRequest() | |||
.authenticated() | |||
// RBAC 动态 url 认证 | |||
@@ -109,11 +106,69 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { | |||
http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); | |||
} | |||
/** | |||
* 放行所有不需要登录就可以访问的请求,参见 AuthController | |||
* 也可以在 {@link #configure(HttpSecurity)} 中配置 | |||
* {@code http.authorizeRequests().antMatchers("/api/auth/**").permitAll()} | |||
*/ | |||
@Override | |||
public void configure(WebSecurity web) throws Exception { | |||
if (CollUtil.isNotEmpty(customConfig.getIgnores())) { | |||
web.ignoring() | |||
.antMatchers(ArrayUtil.toArray(customConfig.getIgnores(), String.class)); | |||
} | |||
public void configure(WebSecurity web) { | |||
WebSecurity and = web.ignoring() | |||
.and(); | |||
// 忽略 GET | |||
customConfig.getIgnores() | |||
.getGet() | |||
.forEach(url -> and.ignoring() | |||
.antMatchers(HttpMethod.GET, url)); | |||
// 忽略 POST | |||
customConfig.getIgnores() | |||
.getPost() | |||
.forEach(url -> and.ignoring() | |||
.antMatchers(HttpMethod.POST, url)); | |||
// 忽略 DELETE | |||
customConfig.getIgnores() | |||
.getDelete() | |||
.forEach(url -> and.ignoring() | |||
.antMatchers(HttpMethod.DELETE, url)); | |||
// 忽略 PUT | |||
customConfig.getIgnores() | |||
.getPut() | |||
.forEach(url -> and.ignoring() | |||
.antMatchers(HttpMethod.PUT, url)); | |||
// 忽略 HEAD | |||
customConfig.getIgnores() | |||
.getHead() | |||
.forEach(url -> and.ignoring() | |||
.antMatchers(HttpMethod.HEAD, url)); | |||
// 忽略 PATCH | |||
customConfig.getIgnores() | |||
.getPatch() | |||
.forEach(url -> and.ignoring() | |||
.antMatchers(HttpMethod.PATCH, url)); | |||
// 忽略 OPTIONS | |||
customConfig.getIgnores() | |||
.getOptions() | |||
.forEach(url -> and.ignoring() | |||
.antMatchers(HttpMethod.OPTIONS, url)); | |||
// 忽略 TRACE | |||
customConfig.getIgnores() | |||
.getTrace() | |||
.forEach(url -> and.ignoring() | |||
.antMatchers(HttpMethod.TRACE, url)); | |||
// 按照请求格式忽略 | |||
customConfig.getIgnores() | |||
.getPattern() | |||
.forEach(url -> and.ignoring() | |||
.antMatchers(url)); | |||
} | |||
} |
@@ -50,5 +50,10 @@ logging: | |||
custom: | |||
config: | |||
ignores: | |||
- "/api/auth/login" | |||
- "/api/auth/logout" | |||
# 需要过滤的 post 请求 | |||
post: | |||
- "/api/auth/login" | |||
- "/api/auth/logout" | |||
# 需要过滤的请求,不限方法 | |||
pattern: | |||
- "/test/*" |