@@ -0,0 +1,29 @@ | |||||
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> | |||||
* 自定义配置 | |||||
* </p> | |||||
* | |||||
* @package: com.xkcoding.rbac.security.config | |||||
* @description: 自定义配置 | |||||
* @author: yangkai.shen | |||||
* @date: Created in 2018-12-13 10:56 | |||||
* @copyright: Copyright (c) 2018 | |||||
* @version: V1.0 | |||||
* @modified: yangkai.shen | |||||
*/ | |||||
@ConfigurationProperties(prefix = "custom.config") | |||||
@Data | |||||
public class CustomConfig { | |||||
/** | |||||
* 不需要拦截的地址 | |||||
*/ | |||||
private List<String> ignores = Lists.newArrayList(); | |||||
} |
@@ -1,5 +1,6 @@ | |||||
package com.xkcoding.rbac.security.config; | package com.xkcoding.rbac.security.config; | ||||
import cn.hutool.core.collection.CollUtil; | |||||
import cn.hutool.core.util.StrUtil; | import cn.hutool.core.util.StrUtil; | ||||
import com.xkcoding.rbac.security.common.Status; | import com.xkcoding.rbac.security.common.Status; | ||||
import com.xkcoding.rbac.security.exception.SecurityException; | import com.xkcoding.rbac.security.exception.SecurityException; | ||||
@@ -12,8 +13,8 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticatio | |||||
import org.springframework.security.core.context.SecurityContextHolder; | import org.springframework.security.core.context.SecurityContextHolder; | ||||
import org.springframework.security.core.userdetails.UserDetails; | import org.springframework.security.core.userdetails.UserDetails; | ||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; | import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; | ||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher; | |||||
import org.springframework.stereotype.Component; | import org.springframework.stereotype.Component; | ||||
import org.springframework.util.AntPathMatcher; | |||||
import org.springframework.web.filter.OncePerRequestFilter; | import org.springframework.web.filter.OncePerRequestFilter; | ||||
import javax.servlet.FilterChain; | import javax.servlet.FilterChain; | ||||
@@ -44,32 +45,41 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { | |||||
@Autowired | @Autowired | ||||
private JwtUtil jwtUtil; | private JwtUtil jwtUtil; | ||||
@Autowired | |||||
private CustomConfig customConfig; | |||||
@Override | @Override | ||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { | protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { | ||||
AntPathMatcher antPathMatcher = new AntPathMatcher(); | |||||
if (antPathMatcher.match("/**/api/auth/**", request.getRequestURI())) { | |||||
filterChain.doFilter(request, response); | |||||
} else { | |||||
String jwt = jwtUtil.getJwtFromRequest(request); | |||||
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 (StrUtil.isNotBlank(jwt)) { | |||||
try { | |||||
String username = jwtUtil.getUsernameFromJWT(jwt); | |||||
String jwt = jwtUtil.getJwtFromRequest(request); | |||||
UserDetails userDetails = customUserDetailsService.loadUserByUsername(username); | |||||
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); | |||||
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); | |||||
if (StrUtil.isNotBlank(jwt)) { | |||||
try { | |||||
String username = jwtUtil.getUsernameFromJWT(jwt); | |||||
SecurityContextHolder.getContext() | |||||
.setAuthentication(authentication); | |||||
filterChain.doFilter(request, response); | |||||
} catch (SecurityException e) { | |||||
ResponseUtil.renderJson(response, e); | |||||
} | |||||
} else { | |||||
ResponseUtil.renderJson(response, Status.UNAUTHORIZED, null); | |||||
UserDetails userDetails = customUserDetailsService.loadUserByUsername(username); | |||||
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); | |||||
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); | |||||
SecurityContextHolder.getContext() | |||||
.setAuthentication(authentication); | |||||
filterChain.doFilter(request, response); | |||||
} catch (SecurityException e) { | |||||
ResponseUtil.renderJson(response, e); | |||||
} | } | ||||
} else { | |||||
ResponseUtil.renderJson(response, Status.UNAUTHORIZED, null); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -1,20 +1,22 @@ | |||||
package com.xkcoding.rbac.security.config; | 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 com.xkcoding.rbac.security.service.CustomUserDetailsService; | ||||
import org.springframework.beans.factory.annotation.Autowired; | 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.Bean; | ||||
import org.springframework.context.annotation.Configuration; | import org.springframework.context.annotation.Configuration; | ||||
import org.springframework.security.authentication.AuthenticationManager; | import org.springframework.security.authentication.AuthenticationManager; | ||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; | ||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity; | import org.springframework.security.config.annotation.web.builders.HttpSecurity; | ||||
import org.springframework.security.config.annotation.web.builders.WebSecurity; | |||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; | ||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; | ||||
import org.springframework.security.config.http.SessionCreationPolicy; | import org.springframework.security.config.http.SessionCreationPolicy; | ||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; | ||||
import org.springframework.security.web.access.AccessDeniedHandler; | import org.springframework.security.web.access.AccessDeniedHandler; | ||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; | import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; | ||||
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; | |||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher; | |||||
/** | /** | ||||
* <p> | * <p> | ||||
@@ -31,7 +33,11 @@ import org.springframework.security.web.util.matcher.AntPathRequestMatcher; | |||||
*/ | */ | ||||
@Configuration | @Configuration | ||||
@EnableWebSecurity | @EnableWebSecurity | ||||
@EnableConfigurationProperties(CustomConfig.class) | |||||
public class SecurityConfig extends WebSecurityConfigurerAdapter { | public class SecurityConfig extends WebSecurityConfigurerAdapter { | ||||
@Autowired | |||||
private CustomConfig customConfig; | |||||
@Autowired | @Autowired | ||||
private AccessDeniedHandler accessDeniedHandler; | private AccessDeniedHandler accessDeniedHandler; | ||||
@@ -76,8 +82,8 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { | |||||
// 认证请求 | // 认证请求 | ||||
.authorizeRequests() | .authorizeRequests() | ||||
// 放行 /api/auth/** 的所有请求,参见 AuthController | // 放行 /api/auth/** 的所有请求,参见 AuthController | ||||
.antMatchers("/**/api/auth/**") | |||||
.permitAll() | |||||
//.antMatchers("/api/auth/**") | |||||
//.permitAll() | |||||
.anyRequest() | .anyRequest() | ||||
.authenticated() | .authenticated() | ||||
// RBAC 动态 url 认证 | // RBAC 动态 url 认证 | ||||
@@ -86,7 +92,8 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { | |||||
// 登出行为由自己实现,参考 AuthController#logout | // 登出行为由自己实现,参考 AuthController#logout | ||||
.and() | .and() | ||||
.logout().disable() | |||||
.logout() | |||||
.disable() | |||||
// Session 管理 | // Session 管理 | ||||
.sessionManagement() | .sessionManagement() | ||||
@@ -101,4 +108,12 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { | |||||
// 添加自定义 JWT 过滤器 | // 添加自定义 JWT 过滤器 | ||||
http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); | http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); | ||||
} | } | ||||
@Override | |||||
public void configure(WebSecurity web) throws Exception { | |||||
if (CollUtil.isNotEmpty(customConfig.getIgnores())) { | |||||
web.ignoring() | |||||
.antMatchers(ArrayUtil.toArray(customConfig.getIgnores(), String.class)); | |||||
} | |||||
} | |||||
} | } |
@@ -47,3 +47,8 @@ jwt: | |||||
logging: | logging: | ||||
level: | level: | ||||
com.xkcoding.rbac.security: debug | com.xkcoding.rbac.security: debug | ||||
custom: | |||||
config: | |||||
ignores: | |||||
- "/api/auth/login" | |||||
- "/api/auth/logout" |