我正在尝试在用户登录Spring Security后实现一个需要操作的屏幕?我有一个要求,用户必须执行以完成表单(更改密码,接受使用条款等),然后一旦用户完成该操作,他就可以使用应用程序的其余部分。我正在使用Spring OAuth2和使用Spring Security流程的登录屏幕。
到目前为止,我尝试使用具有http.formLogin().successHandler()
自定义实现的SavedRequestAwareAuthenticationSuccessHandler
,它会检测用户是否需要执行操作,然后在用户填写表单时将用户重定向到该页面,但是问题是,如果用户离开该页面,他将登录到该应用程序,并且可以在不跳过表单的情况下使用它。但我要做的是阻止用户建立会话,直到完成Action Action表单之后。一旦完成,用户应自动登录(例如,如果用户需要同意使用条款,他应该在没有第二次输入密码的情况下登录)
以下是我到目前为止自定义处理程序的代码:
public class CustomLoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
@Autowired
UserService userService;
public final static String TARGET_URL_SESSION_ATTR_NAME = "target-url";
public CustomLoginSuccessHandler(String defaultTargetUrl) {
setDefaultTargetUrl(defaultTargetUrl);
}
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException {
HttpSession session = request.getSession();
AuthorityUser authorityUser = (AuthorityUser)authentication.getPrincipal();
String userId = authorityUser.getUserId();
User u = userService.getById(userId);
Boolean changeRequiredDob = u.getChangeRequiredDob();
Boolean changeRequiredPwd = u.getChangeRequiredPwd();
Boolean changeRequiredTou = u.getChangeRequiredTou();
if(changeRequiredDob || changeRequiredPwd || changeRequiredTou){
String targetUrl = determineTargetUrl(request, response);
session.setAttribute(TARGET_URL_SESSION_ATTR_NAME, targetUrl);
getRedirectStrategy().sendRedirect(request, response, "/action-required");
} else {
super.onAuthenticationSuccess(request, response, authentication);
}
}
}
然后,一旦成功完成,我就会将用户重定向到存储在会话中的TARGET_URL_SESSION_ATTR_NAME
。
知道如何在建立的会话期间检测用户并将用户重定向到需要操作的屏幕(如果用户登录以及稍后在他的帐户中登录管理员设置操作所需标志时),这也会有所帮助。
答案 0 :(得分:3)
https://github.com/king-julien/spring-oauth2-customfilter以下是授权和资源服务器的工作示例。此资源服务器(vanilla)是一个基本的无状态应用程序,除非您在身份验证后接受服务条款(接受TOS,只是在/ tos端点上执行POST),否则将不再继续执行。
@Component
public class TosFilter extends OncePerRequestFilter{
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
System.out.println(request.getRequestURI());
// In realworld scenario HelloWorldController.acceptedTOS is a persisted value rather than a static variable
if(!HelloWorldController.acceptedTOS){
//response.sendRedirect("/no-tos");
request.getRequestDispatcher("error-no-tos").forward(request, response);
}
filterChain.doFilter(request,response);
}
}
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
TosFilter rolesFilter;
@Override
public void configure(HttpSecurity httpSecurity) throws Exception{
httpSecurity
.addFilterAfter(rolesFilter, AbstractPreAuthenticatedProcessingFilter.class)
.csrf().disable()
.authorizeRequests().anyRequest().permitAll();
}
}
@SpringBootApplication
@EnableResourceServer
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
答案 1 :(得分:1)
我们解决的方法是让OAuth2批准页面成为单页面应用程序。 默认情况下,批准页面控制器是WhitelabelApprovalEndpoint。我们通过定义自己的OauthApproval Controller来覆盖它,它覆盖" / oauth / confirm_access",因此我们可以为模型添加额外的东西。当加载批准(jsp)页面时,我们将一些模型属性转换为javascript变量(var token =' $ {_ csrf.token}';),并启动AngularJS应用程序。批准页面可以随意执行(在显示实际批准表单之前),我们只需要为不同的功能构建REST端点。
请记住将@SessionAttributes(" authorizationRequest")添加到控制器
答案 2 :(得分:1)
而不是AuthenticationSuccessHandler
你应该使用过滤器:
public class ActionRequirementCheckingFilter extends OncePerRequestFilter {
/* This matcher should not match static resources (js,css etc),
* url`s needed to handle the action and possibly something else,
* depending on your application */
private RequestMatcher matcher;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
HttpSession session = request.getSession();
Boolean actionRequired = false;
/* calculate actual value for actionRequired */
if(matcher.matches(request) && actionRequired){
/* save current request info into session for later use if needed */
response.sendRedirect("/action-required");
} else {
filterChain.doFilter(request, response);
}
}
}
这种方法符合您的所有要求:
唯一的缺点是会在操作完成之前实际创建会话,但除非你有真正的理由不这样做(我甚至无法成像),这可以忽略不计。
答案 3 :(得分:0)
在成功登录会话期间验证用户访问权限的另一种方法是通过过滤器api
https://www.mkyong.com/spring-mvc/how-to-register-a-servlet-filter-in-spring-mvc/
然后,您可以实现doFilter()中所需的功能来验证您的规则。