是否有可能在同一项目中同时使用两种身份验证。
是的你可以。通过具有两个身份验证处理过滤器。
过滤器-1 :用于Rest
API(JwtAuthTokenFilter),该API应该是无状态的,并由每次请求中发送的Authorization令牌标识。
过滤器2
:您需要另一个过滤器(UsernamePasswordAuthenticationFilter)默认情况下,如果通过进行配置,spring-
security将提供此过滤器
http.formLogin()。在这里,每个请求都由
JSESSIONID关联的session(cookie)标识。如果请求中不包含有效的会话,则它将被重定向到身份验证入口点(例如:login-
page)。
推荐的网址格式
api-url-pattern = "/api/**"webApp-url-pattern = "/**"
怎么运行的
URL的
/api/**
将会通过JwtAuthTokenFilter
它将读取令牌的地方传递,如果它具有有效的令牌,则设置身份验证对象,并继续进行链接。如果没有有效的请求,则链会断开,并且将以401(未授权)状态发送响应。URL以外的其他
/api/**
将由UsernamePasswordAuthenticationFilter
[将由.formLogin()
配置配置的Spring Security中的默认值]处理。它将检查有效的会话,如果它不包含有效的会话,它将重定向到配置的logoutSuccessUrl。
注意: 您的Webapp无法使用现有会话访问API。您具有的选择是使用Jwt令牌从Web应用程序访问API。
如何配置
要实现两个不同的身份验证处理过滤器,您应该以不同的顺序配置多个http安全配置,
可以通过在安全配置类中声明静态类来配置多个http安全配置,如下所示。
(即使OP要求在概念上明智地将代码明智地呈现出来,也可能有助于您参考)
Spring安全配置
@Configuration@EnableWebSecurity@ComponentScan(basePackages = "com.gmail.nlpraveennl")public class SpringSecurityConfig{ @Bean public PasswordEnprer passwordEnprer() { return new BCryptPasswordEnprer(); } @Configuration @Order(1) public static class RestApiSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private JwtAuthenticationTokenFilter jwtauthFilter; @Override protected void configure(HttpSecurity http) throws Exception { http .csrf().disable() .antMatcher("/api/**") .authorizeRequests() .antMatchers("/api/authenticate").permitAll() .antMatchers("/api/**").hasAnyRole("APIUSER") .and() .addFilterBefore(jwtauthFilter, UsernamePasswordAuthenticationFilter.class); http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); } } @Configuration @Order(2) public static class LoginFormSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private PasswordEnprer passwordEnprer; @Autowired public void configureInMemoryAuthentication(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication().withUser("admin").password(passwordEnprer.enpre("admin@123#")).roles("ADMIN"); } @Override protected void configure(HttpSecurity http) throws Exception { http .csrf().disable() .antMatcher("/**").authorizeRequests() .antMatchers("/resources/**").permitAll() .antMatchers("/**").hasRole("ADMIN") .and().formLogin(); http.sessionManagement().maximumSessions(1).expiredUrl("/customlogin?expired=true"); } }}JWT身份验证令牌过滤器
@Componentpublic 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)) { List<GrantedAuthority> authList = new ArrayList<>(); authList.add(new SimpleGrantedAuthority("ROLE_APIUSER")); UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(username, null, authList); 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); }}Jwt令牌util类
@Componentpublic 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> T getClaimFromToken(String token, Function<Claims, T> 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<String, Object> claims = new HashMap<>(); return doGenerateToken(claims, username); } private String doGenerateToken(Map<String, Object> 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)); }}分派器Servlet配置
@Configuration@EnableWebMvc@ComponentScan(basePackages = "com.gmail.nlpraveennl") //Do not skip componentscanpublic class ServletConfiguration implements WebMvcConfigurer{ @Bean public ViewResolver configureViewResolver() { InternalResourceViewResolver viewResolve = new InternalResourceViewResolver(); viewResolve.setPrefix("/WEB-INF/jsp/"); viewResolve.setSuffix(".jsp"); return viewResolve; } @Bean public ResourceBundleMessageSource messageSource() { ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); messageSource.setbasename("messages"); messageSource.setDefaultEncoding("UTF-8"); messageSource.setUseCodeAsDefaultMessage(true); return messageSource; } @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/resources/**").addResourceLocations("/resources/"); }}


