在 Spring Security UsernamePasswordAuthenticationFilter JWT 身份验证中设置自定义登录 url
Posted
技术标签:
【中文标题】在 Spring Security UsernamePasswordAuthenticationFilter JWT 身份验证中设置自定义登录 url【英文标题】:Set custom login url in Spring Security UsernamePasswordAuthenticationFilter JWT authentication 【发布时间】:2018-04-04 00:01:33 【问题描述】:我正在关注 this auth0's tutorial 以使用 JWT 保护我的应用程序。
我最终得到了以下 WebSecurity 配置:
@EnableWebSecurity
@AllArgsConstructor(onConstructor = @__(@Autowired))
public class WebSecurity extends WebSecurityConfigurerAdapter
private final UserDetailsService userDetailsService;
private final BCryptPasswordEncoder passwordEncoder;
@Override
protected void configure(HttpSecurity http) throws Exception
http.formLogin()
.and().cors()
.and().csrf()
.disable()
.authorizeRequests()
.antMatchers(HttpMethod.POST, REGISTER_URL).permitAll()
.antMatchers(HttpMethod.POST, LOGIN_URL).permitAll()
.anyRequest().authenticated()
.and()
.addFilter(new JWTAuthorizationFilter(authenticationManager()))
.addFilter(new JWTAuthenticationFilter(authenticationManager()))
// This disables session creation on Spring Security
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
@Bean
public CorsConfigurationSource corsConfigurationSource()
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
return source;
以及以下 JWTAuthenticationFilter:
public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter
private final AuthenticationManager authenticationManager;
public JWTAuthenticationFilter(AuthenticationManager authenticationManager)
this.authenticationManager = authenticationManager;
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException
try
ApplicationUser credentials = new ObjectMapper().readValue(request.getInputStream(), ApplicationUser.class);
return authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(
credentials.getUsername(),
credentials.getPassword(),
new ArrayList<>()
)
);
catch (IOException e)
throw new RuntimeException(e);
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException
String token = Jwts.builder()
.setSubject(((User) authResult.getPrincipal()).getUsername())
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
.signWith(SignatureAlgorithm.HS512, SECRET.getBytes())
.compact();
response.addHeader(HEADER_STRING, TOKEN_PREFIX + token);
目前,该应用接受/login
URL 上的POST 请求。我想知道如何将 URL 更改为,比如说,/api/auth/login
。有没有办法将 URL 字符串注入身份验证过滤器或在安全配置中以某种方式设置它?
【问题讨论】:
【参考方案1】:您正在扩展 org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter,它本身扩展
org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter。在最后一个类中,有一个名为 setFilterProcessesUrl
的 setter 旨在执行此操作:
setFilterProcessesUrl
public void setFilterProcessesUrl(String filterProcessesUrl)
设置确定是否需要身份验证的 URL
参数:filterProcessesUrl
This 是指向该 javadoc 部分的链接
所以在你的WebSecurityConfigurerAdapter
中你可以这样做:
@Bean
public JWTAuthenticationFilter getJWTAuthenticationFilter()
final JWTAuthenticationFilter filter = new JWTAuthenticationFilter(authenticationManager());
filter.setFilterProcessesUrl("/api/auth/login");
return filter;
然后在同一类中的 configure
方法中只引用它而不是创建新实例:
.addFilter(getJWTAuthenticationFilter())
【讨论】:
谢谢,这很有魅力!不过,您的回答中有一个小疏忽,您将 JWTAuthorizationFilter 与 JWTAuthenticationFilter 混淆了。但是,它仍然可以完美运行。 我们可以在springboot中用oauth2自己的资源服务器做同样的事情吗? @YasirShabbirChoudhary 我想是这样,但完全不确定。你可以试一试,如果它不起作用,你可以发布一个问题,我会检查它 @jilumietu - 谢谢你的回答。我有一个问题要问你。是否可以通过这种方式使 Spring 安全性允许其他方法如 DELETE 或 PUT 到 filterprocessesUrl? @KavithaKarunakaran,我没有测试过它,但它应该。方法AbstractAuthenticationProcessingFilter.setFilterProcessesUrl(String filterProcessesUrl)
内部调用setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher(filterProcessesUrl));
。构造函数AntPathRequestMatcher(String filterProcessesUrl)
将HttpMethod httpMethod
属性初始化为null,这使得public boolean matches(HttpServletRequest request)
方法不会评估传入的HttpServletRequest
方法。所以根据这个,其他方法肯定可以工作【参考方案2】:
一个小的改进可能是只使用自定义进程 url 创建您的过滤器并使用它而不创建我认为您在此处以外的任何地方都不需要的 bean。
JWTAuthenticationFilter authenticationFilter = new JWTAuthenticationFilter(authenticationManager());
authenticationFilter.setFilterProcessesUrl("/mobile/login");
....
.and()
.addFilter(authenticationFilter)
.addFilter(new JWTAuthenticationFilter(authenticationManager()))
【讨论】:
以上是关于在 Spring Security UsernamePasswordAuthenticationFilter JWT 身份验证中设置自定义登录 url的主要内容,如果未能解决你的问题,请参考以下文章
在运行时延迟初始化 Spring Security + 重新加载 Spring Security 配置
在使用 Oauth、SAML 和 spring-security 的多租户的情况下从 spring-security.xml 中获取错误
Spring Security 入门(1-11)Spring Security - 匿名认证
使用 spring-session 和 spring-cloud-security 时,OAuth2ClientContext (spring-security-oauth2) 不会保留在 Redis