spring-boot - 春季启动安全自定义successHandler,其余不工作
问题描述
不知道我的问题是否好..
也许我在寻找有关spring security的信息时非常糟糕。总的来说,我希望您不会很难回答。
问题是,我在登录页面中使用了 Spring Security。登录页面位于公共模板文件夹中。我没有为它创建一个单独的控制器来返回视图页面(为它创建一个控制器来返回视图登录页面是否正确?)。无论如何,即使没有这个页面视图控制器,我的代码也能工作。但只有我的自定义 SuccessHandler 不起作用(登录后,按角色检查并重定向到另一个页面)。我应该使用不同的方法按角色重定向到适当的页面吗?(我的意思是如果登录后的 ADMIN_ROLE 被重定向到 admin-panel.html)
我的安全
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class CustomWebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private UserServiceImpl userServiceImpl;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and()
.authorizeRequests()
.antMatchers("/", "/templates/sign-up.html").permitAll()
.antMatchers("/api/users", "/api/users/login").permitAll()
.antMatchers("/templates/admin-panel.html").hasRole("ADMIN")
.antMatchers("/all-users").hasRole("ADMIN")
.antMatchers("/news").hasRole("USER")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/templates/login.html")
.defaultSuccessUrl("/")
.permitAll()
.successHandler(myAuthenticationSuccessHandler())
.and()
.logout()
.permitAll()
.logoutSuccessUrl("/index.html");
http.csrf().disable();
}
@Override
public void configure(WebSecurity web) {
web
.ignoring()
.antMatchers("/css/**")
.antMatchers("/js/**")
.antMatchers("/static/**")
.antMatchers("/resources/**");
}
@Autowired
protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userServiceImpl).passwordEncoder(bCryptPasswordEncoder());
}
@Bean
public AuthenticationSuccessHandler myAuthenticationSuccessHandler(){
return new CustomAuthenticationSuccessHandler();
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
我的自定义成功处理程序
public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
protected final Log logger = LogFactory.getLog(this.getClass());
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
public CustomAuthenticationSuccessHandler() {
super();
}
// API
@Override
public void onAuthenticationSuccess(final HttpServletRequest request, final HttpServletResponse response, final Authentication authentication) throws IOException {
handle(request, response, authentication);
clearAuthenticationAttributes(request);
}
// IMPL
protected void handle(final HttpServletRequest request, final HttpServletResponse response, final Authentication authentication) throws IOException {
final String targetUrl = determineTargetUrl(authentication);
if (response.isCommitted()) {
logger.debug("Response has already been committed. Unable to redirect to " + targetUrl);
return;
}
redirectStrategy.sendRedirect(request, response, targetUrl);
}
protected String determineTargetUrl(final Authentication authentication) {
Map<String, String> roleTargetUrlMap = new HashMap<>();
roleTargetUrlMap.put("ROLE_USER", "/index.html");
roleTargetUrlMap.put("ROLE_ADMIN", "/templates/admin-panel.html");
final Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
for (final GrantedAuthority grantedAuthority : authorities) {
String authorityName = grantedAuthority.getAuthority();
if(roleTargetUrlMap.containsKey(authorityName)) {
return roleTargetUrlMap.get(authorityName);
}
}
throw new IllegalStateException();
}
/**
* Removes temporary authentication-related data which may have been stored in the session
* during the authentication process.
*/
protected final void clearAuthenticationAttributes(final HttpServletRequest request) {
final HttpSession session = request.getSession(false);
if (session == null) {
return;
}
session.removeAttribute(WebAttributes.AUTHENTICATION_EXCEPTION);
}
}
我的控制器
@CrossOrigin
@RestController
@RequestMapping("/api/users")
public class UserController {
private final UserServiceImpl userService;
private AuthenticationManager authenticationManager;
public UserController(UserServiceImpl userService, AuthenticationManager authenticationManager) {
this.userService = userService;
this.authenticationManager = authenticationManager;
}
@PostMapping
public ResponseEntity<?> register(@RequestBody UserDTO user) {
try {
userService.register(user);
return new ResponseEntity<>("User added", HttpStatus.OK);
} catch (Exception e) {
return new ResponseEntity<>(e, HttpStatus.BAD_REQUEST);
}
}
@PostMapping(value = "/login")
public ResponseEntity<?> login(@RequestBody UserDTO user, HttpServletResponse response) {
try {
Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword()));
boolean isAuthenticated = isAuthenticated(authentication);
if (isAuthenticated) {
SecurityContextHolder.getContext().setAuthentication(authentication);
// response.sendRedirect("/templates/admin-panel.html");
// my pathetic attempt to create a redirect to another page
}
return new ResponseEntity<>("user authenticated", HttpStatus.OK);
} catch (Exception e) {
return new ResponseEntity<>(e, HttpStatus.FORBIDDEN);
}
}
private boolean isAuthenticated(Authentication authentication) {
return authentication != null && !(authentication instanceof AnonymousAuthenticationToken) && authentication.isAuthenticated();
}
我的静态文件 在此处输入图像描述
解决方案
我猜,因为您没有发布登录页面本身:
您不需要一个控制器来监听POST /login
这个通常由 Spring Security 自动注册的所有与安全相关的身份验证内容。无需像在 中那样自己尝试UserController.login()
。我想通过注册这个端点,你会覆盖/停用常规的 spring 安全行为。
通常,您只需要一个登录页面,其中包含正确发布到 /login 的表单。后端的处理由 Spring Security 本身完成。
有关最小的工作设置,请参阅https://spring.io/guides/gs/securering-web/ 。
推荐阅读
- c# - Xamarin 和 .NET Standard 2 库问题
- vb.net - 将整数加一
- amazon-web-services - ClientError:调用 AssumeRole 操作时发生错误(AccessDenied):MultiFactorAuthentication failed with invalid MFA one time pass code
- c# - 目录右键
- sql - PostgreSQL 使用来自不同表列的自动计算列创建表
- asp.net-core-mvc - 找不到方法:'无效 EntityFrameworkCore.Design.Internal.DbContextOperations
- c# - C#在分配之前设置字符串长度并在剩余位置添加空格
- javascript - Vue.js 访问组件方法还是父方法?
- python - Python:具有多个标题的 CSV 文件 - 组合成一个数据框?
- powerbi - 在子项目类别 powerbi 上过滤项目