我有一个Spring Boot应用程序。我有2个登录页面,用于系统中的2组不同用户。
任何以/expert
开头的网址,用户都应具有EXPERT
或ADMIN
的角色。用户使用表单登录登录系统,登录页面路径为/login
。
对于某些网址,例如css
,js
等,不需要进行身份验证。
对于所有其他URL,用户不需要特殊角色,身份验证就足够了。用户的登录页面应为/loginTwo
。
我查看了this stackoverflow问题和this文档来实现这一点。但是,当我访问包含/expert
的网址时,我会转到登录页面/loginTwo
,而不是/login
。
以下是我的代码:
@Autowired
@Qualifier("userService")
UserDetailsService userDetailsService;
@Bean
public PasswordEncoder passwordEncoder() {
PasswordEncoder encoder = new Md5PasswordEncoder();
return encoder;
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Configuration
@Order(1)
public static class ExpertWebSecurity extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/login/**").permitAll();
http
.antMatcher("/expert/**")
.authorizeRequests()
.anyRequest().access("hasRole('ROLE_ADMIN') or hasRole('ROLE_EXPERT')")
.and()
.formLogin()
.loginPage("/login").permitAll();
}
}
@Configuration
public static class StudentWebSecurity extends WebSecurityConfigurerAdapter{
@Override
protected void configure(HttpSecurity http) throws Exception {
System.out.println("Here in stu");
http
.authorizeRequests()
.antMatchers("/css/**,/js/**").permitAll()
.antMatchers("/error/**").permitAll()
.antMatchers("/student/**").permitAll()
.antMatchers("/filter/**").permitAll()
.antMatchers("/loginTwo").permitAll()
.antMatchers("/admin/**").access("hasRole('ROLE_ADMIN') or hasRole('ROLE_EXPERT')")
.antMatchers("/").permitAll()
.anyRequest().authenticated()
.and()
.csrf();
http
.formLogin()
.loginPage("/loginTwo").permitAll()
.and()
.logout().permitAll();
http
.sessionManagement()
.maximumSessions(20)
.expiredUrl("/loginTwo")
.maxSessionsPreventsLogin(false);
http
.headers().addHeaderWriter(new XFrameOptionsHeaderWriter(XFrameOptionsMode.SAMEORIGIN));
}
}
请你帮我解决这个问题。
答案 0 :(得分:0)
您需要为每个不同的端点添加不同的身份验证过滤器。
对于HttpSecurity
,您可以定义类似的内容,为构造函数提供UserDetailsService
并传递身份验证管理器:
.addFilterBefore(new FirstLoginFilter("/api/login/first", userDetailsService, authenticationManager()), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(new SecondLoginFilter("/api/login/second", userDetailsService, authenticationManager()), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(new AdminLoginFilter("/api/login/admin", userDetailsService, authenticationManager()), UsernamePasswordAuthenticationFilter.class)
过滤器的实现看起来像这样。
让我们从抽象认证过滤器开始,它是上述所有过滤器的父级:
public abstract class LoginFilter extends AbstractAuthenticationProcessingFilter {
protected final SimpleUserDetailsService userService;
public LoginFilter(String pattern, SimpleUserDetailsService userService, AuthenticationManager authManager) {
super(new AntPathRequestMatcher(pattern));
this.userService = userService;
this.setAuthenticationManager(authManager);
this.setAuthenticationSuccessHandler(new FormAuthenticationSuccessHandler());
this.setAuthenticationFailureHandler(new FormAuthenticationFailureHandler());
}
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authentication) throws ServletException {
User authenticatedUser = this.userService.loadUserByUsername(authentication.getName());
UserAuthentication userAuthentication = new UserAuthentication(authenticatedUser);
SecurityContextHolder.getContext().setAuthentication(userAuthentication);
}
}
例如,实际过滤器的一个实现:
public class FirstLoginFilter extends LoginFilter {
public FirstLoginFilter(String pattern, SimpleUserDetailsService userDetailsService, AuthenticationManager authManager) {
super(pattern, userDetailsService, authManager);
}
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
User user = (User)(new ObjectMapper()).readValue(request.getInputStream(), User.class);
UsernamePasswordAuthenticationToken loginToken = new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword());
Authentication authentication = this.getAuthenticationManager().authenticate(loginToken);
if(!Role.isRolePresent(authentication.getAuthorities(), Role.YOUR_ROLE)) {
throw new BadCredentialsException("Bad credentials");
} else {
return authentication;
}
}
}
我的示例使用无状态身份验证机制,因此您需要相应地修改过滤器。正如我从您的初始示例中看到的那样,您正在使用会话,因此实际上它应该更容易,因为它已经内置于Spring Security中
希望它有所帮助。