开云访问入口

3年前 (2023-03-22)

我有你的要求

  1. 您需要在请求标头(针对每个请求)中公开应通过JWT令牌访问的API。 同题参见

  2. Web应用程序也应通过基于表单的身份验证机制来保护,该机制应基于http会话进行工作。 对照阅读

您可以通过两个身份验证过滤器来实现。

:用于Rest API(JwtAuthTokenFilter),该API应该是无状态的,并由每次请求中发送的Authorization令牌标识。 相关阅读 :您需要另一个过滤器(UsernamePasswordAuthenticationFilter)默认情况下,如果通过进行配置,spring- security将提供此过滤器http.formLogin()。在这里,每个请求都由JSESSIONID关联的session(cookie)标识。如果请求中不包含有效的会话,则它将被重定向到身份验证入口点(例如:login- page)。

api-url-pattern = "/api/**" [strictly for @order(1)]
webApp-url-pattern = "/**" [ wild card "/**" always used for higer order otherwise next order configuration becomes dead configuration]
方法
  • 定义主配置类@EnableWebSecurity

  • 创建两个内部静态类,它们应WebSecurityConfigurerAdapter使用@Configuration和@Order进行扩展和注释。在此,REST API配置的顺序应为1,Web应用程序配置的顺序应大于1

  • 请参阅 ,其中 解释了必要的代码。如果需要,请随时从github存储库中请求可下载的链接。

在这里,两个过滤器将并排(平行)工作。我的意思是从Web应用程序开始,即使用户通过会话进行了身份验证,但如果没有JWT令牌,他也无法访问API。

OP的要求,即他不想定义任何角色,但允许经过身份验证的用户进行API访问。根据他的要求修改了以下配置。

http.csrf().disable()
.antMatcher("/web/umgmt/**").authorizeRequests()
.antMatcher("/web/umgmt/**").authenticated() // use this
解决方法

我已经为我的应用程序安装了Spring Security
Cookie机制,现在仅针对API。我需要添加基于JWT令牌的身份验证机制。一般来说我正在使用带有两个嵌套类的Spring
Security的MultiHttpSecurityConfiguration。

会话和JWT令牌机制是否应该一起包含在一个应用程序中是一个完全不同的问题。我需要实现两件事。

  1. Spring Security的基于cookie的基于会话的身份验证将像以前一样工作。

  2. 需要为API添加身份验证标头

 package com.leadwinner.sms.config;

 import java.util.Collections;

 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.ComponentScan;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.core.annotation.Order;
 import org.springframework.security.authentication.AuthenticationManager;
 import org.springframework.security.authentication.ProviderManager;
 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.security.crypto.password.PasswordEncoder;
 import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
 import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
 import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;

 import com.leadwinner.sms.CustomAuthenticationSuccessHandler;
 import com.leadwinner.sms.CustomLogoutSuccessHandler;
 import com.leadwinner.sms.config.jwt.JwtAuthenticationProvider;
 import com.leadwinner.sms.config.jwt.JwtAuthenticationTokenFilter;
 import com.leadwinner.sms.config.jwt.JwtSuccessHandler;

 @EnableWebSecurity
 @EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled = true)
 @ComponentScan(basePackages = "com.leadwinner.sms")
 public class MultiHttpSecurityConfig {

 @Autowired
 @Qualifier("userServiceImpl")
 private UserDetailsService userServiceImpl;

 @Autowired
 private JwtAuthenticationProvider authenticationProvider;

 @Autowired
 public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
 auth.userDetailsService(userServiceImpl).passwordEncoder(passwordEncoder());
 }

 @Bean
 public PasswordEncoder passwordEncoder() {
 return new BCryptPasswordEncoder();
 }

 @Bean
 public AuthenticationManager authenticationManager() {
 return new ProviderManager(Collections.singletonList(authenticationProvider));
 }

 @Configuration
 @Order(1)
 public static class JwtSecurityConfig extends WebSecurityConfigurerAdapter {

 @Autowired
 private JwtAuthenticationTokenFilter jwtauthFilter;

 @Override
 public void configure(HttpSecurity http) throws Exception {
 http.csrf().disable()
 .antMatcher("/web/umgmt/**").authorizeRequests()
 .antMatchers("/web/umgmt/**").authenticated()
 .and()
 .addFilterBefore(jwtauthFilter,UsernamePasswordAuthenticationFilter.class);
 http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
 }
 }

 @Configuration
 @Order(2)
 public static class SecurityConfig extends WebSecurityConfigurerAdapter {
 private final Logger logger = LoggerFactory.getLogger(SecurityConfig.class);

 @Bean
 public CustomAuthenticationEntryPoint getBasicAuthEntryPoint() {
 return new CustomAuthenticationEntryPoint();
 }

 @Override
 public void configure(HttpSecurity http) throws Exception {

 logger.info("http configure");
 http
 .antMatcher("/**").authorizeRequests() 
 .antMatchers("/login/authenticate").permitAll()
 .antMatchers("/resources/js/**").permitAll()
 .antMatchers("/resources/css/**").permitAll()
 .antMatchers("/resources/images/**").permitAll()
 .antMatchers("/web/initial/setup/**").permitAll()
 .antMatchers("/dsinput/**").permitAll().antMatchers("/dsoutput/**").permitAll() 

 .and()
 .formLogin()
 .loginPage("/login").usernameParameter("employeeId").passwordParameter("password")
 .successForwardUrl("/dashboard")
 .defaultSuccessUrl("/dashboard",true)
 .successHandler(customAuthenticationSuccessHandler())
 .failureForwardUrl("/logout")
 .loginProcessingUrl("/j_spring_security_check")
 .and().logout()
 .logoutSuccessUrl("/logout").logoutUrl("/j_spring_security_logout")
 .logoutSuccessHandler(customLogoutSuccessHandler())
 .permitAll()
 .invalidateHttpSession(true)
 .deleteCookies("JSESSIONID")
 .and().sessionManagement()
 .sessionFixation().none()
 .sessionCreationPolicy(SessionCreationPolicy.ALWAYS)
 .invalidSessionUrl("/logout")
 .and().exceptionHandling().accessDeniedPage("/logout").and().csrf().disable();
 http.authorizeRequests().anyRequest().authenticated();


 }

 @Bean
 public AuthenticationSuccessHandler customAuthenticationSuccessHandler() {
 return new CustomAuthenticationSuccessHandler();
 }

 @Bean
 public LogoutSuccessHandler customLogoutSuccessHandler() {
 return new CustomLogoutSuccessHandler();
 }
 }
 }

JwtAuthenticationTokenFilter.java

 package com.leadwinner.sms.config.jwt;

 import java.io.IOException;

 import javax.servlet.FilterChain;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;

 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
 import org.springframework.web.filter.OncePerRequestFilter;

 public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
 @Autowired
 private JwtTokenUtil jwtTokenUtil;

 @Override
 protected void doFilterInternal(HttpServletRequest request,HttpServletResponse response,FilterChain chain)
 throws ServletException,IOException {
 final String header = request.getHeader("Authorization");

 if (header != null && header.startsWith("Bearer ")) {
 String authToken = header.substring(7);
 System.out.println(authToken);

 try {
 String username = jwtTokenUtil.getUsernameFromToken(authToken);
 if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
 if (jwtTokenUtil.validateToken(authToken,username)) {
 UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
 username,null,null);
 usernamePasswordAuthenticationToken
 .setDetails(new WebAuthenticationDetailsSource().buildDetails(request));

 SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
 }
 }
 } catch (Exception e) {
 System.out.println("Unable to get JWT Token,possibly expired");
 }
 }

 chain.doFilter(request,response);
 }
 }

JwtTokenUtil.java

 package com.leadwinner.sms.config.jwt;

 import java.io.Serializable;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.function.Function;

 import org.springframework.stereotype.Component;

 import io.jsonwebtoken.Claims;
 import io.jsonwebtoken.Jwts;
 import io.jsonwebtoken.SignatureAlgorithm;

 @Component
 public class JwtTokenUtil implements Serializable {
 private static final long serialVersionUID = 8544329907338151549L;
 public static final long JWT_TOKEN_VALIDITY = 5 * 60 * 60;
 private String secret = "my-secret";

 public String getUsernameFromToken(String token) {
 return getClaimFromToken(token,Claims::getSubject);
 }

 public Date getExpirationDateFromToken(String token) {
 return getClaimFromToken(token,Claims::getExpiration);
 }

 public  T getClaimFromToken(String token,Function claimsResolver) {
 final Claims claims = getAllClaimsFromToken(token);
 return claimsResolver.apply(claims);
 }

 private Claims getAllClaimsFromToken(String token) {
 return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
 }

 private Boolean isTokenExpired(String token) {
 final Date expiration = getExpirationDateFromToken(token);
 return expiration.before(new Date());
 }

 public String generateToken(String username) {
 Map claims = new HashMap<>();
 return doGenerateToken(claims,username);
 }

 private String doGenerateToken(Map claims,String subject) {
 return "Bearer "
 + Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis()))
 .setExpiration(new Date(System.currentTimeMillis() + JWT_TOKEN_VALIDITY * 1000))
 .signWith(SignatureAlgorithm.HS512,secret).compact();
 }

 public Boolean validateToken(String token,String usernameFromToken) {
 final String username = getUsernameFromToken(token);
 return (username.equals(usernameFromToken) && !isTokenExpired(token));
 }
 }

看来JwtSecurityConfig筛选器现在并未应用于我提到的路径。任何帮助将不胜感激。

我已经读过这个问题。我也一样。

带有Spring Boot的SpringSecurity:将基本身份验证与JWT令牌身份验证混合

编辑:添加了JwtAuthenticationTokenFilter,JwtTokenUtil

总结

以上是真正的电脑专家为你收集整理的Spring Security MultiHttpSecurity配置,这样我就可以执行两种身份验证。JWT令牌和会话Cookie的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得真正的电脑专家网站内容还不错,欢迎将真正的电脑专家推荐给好友。

你可能想看:

继续阅读

若需了解「开云访问入口」的上下文,可结合站内栏目与相关篇目交叉阅读。

栏目用于追新,文内链接用于对照细节。两者配合可减少漏读与重复检索。

继续浏览时优先选择同栏目或相近主题,避免被站外镜像带偏。

站点导览

string · wiki · 科技 · 文化

页面按栏目组织。可先看导读,再进入相关篇目或返回列表。