当(在Spring Security/MVC中)对页面的访问被拒绝时,由于用户没有足够的权限(尽管他已经过身份验证),我需要通过显示登录页面(而不是显示403拒绝访问页面的标准行为)来提供以其他用户身份登录。
我可以写一个AccessDeniedHandler
,重定向到登录页面。但是,当 Spring Security 发现有其他用户登录时,它将如何反应?当新用户成功进行身份验证时,我可以以某种方式注销旧用户吗?
当已经有另一个用户登录时,我尝试登录一个新用户。它可以工作 - 无需注销第一个用户。他的授权被新的授权所取代。这是我自己问题的简单答案。
如果有人感兴趣,如何在访问被拒绝的情况下转发到登录页面 - 这是我的解决方案:
首先定义一个自定义 RequestCache:
@Component("myRequestCache")
public class MyRequestCache extends HttpSessionRequestCache {
public MyRequestCache() {
super();
}
}
其次定义自定义访问拒绝处理程序:
@Component("myAccessDeniedHandler")
public class MyAccessDeniedHandler implements AccessDeniedHandler {
@Autowired
@Qualifier("myRequestCache")
private RequestCache myRequestCache;
public MyAccessDeniedHandler() {
}
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException exc)
throws IOException, ServletException {
if (!response.isCommitted()) {
//Save Target-Request
myRequestCache.saveRequest(request, response);
//Forward to the login page
request.getRequestDispatcher("/loginPage").forward(request, response);
}
}
}
第三,将这两个配置到Spring Security中:
@Configuration
@EnableWebSecurity
public class myConfig extends WebSecurityConfigurerAdapter {
@Autowired
@Qualifier("myRequestCache")
RequestCache myRequestCache;
@Autowired
@Qualifier("myAccessDeniedHandler")
AccessDeniedHandler myAccessDeniedHandler;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestCache()
.requestCache(myRequestCache)
.and()
.exceptionHandling()
.accessDeniedHandler(myAccessDeniedHandler)
}
}
这是怎么回事?MyAccessDeniedHandler
在AccessDeniedException
登录页面的情况下转发。由于这个转发是由这个自编程类调用的,而不是由过滤器链中的 Spring 调用的,我们必须告诉 spring,目标请求是什么 - 在成功身份验证后它必须重定向到哪里。我们通过RequestCache
做到这一点。
如果您想注销旧用户,我建议使用SessionRegistry
(http://docs.spring.io/spring-security/site/docs/current/apidocs/org/springframework/security/core/session/SessionRegistry.html)
一些提示:
在弹簧配置类中
@Configuration
class MyConfiguration{
@Bean
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
}
在您的AccessDeniedHandler
:
@Autowired
private SessionRegistry sessionRegistry;
....
List<SessionInformation> sessionInformations = sessionRegistry.getAllSessions("an-user", false);
for(SessionInformation session: sessionInformations) {
session.expireNow();
}
<</div>
div class="one_answers">您可以在 spring 安全xml
文件中添加以下标签。
<http auto-config="true" use-expressions="true">
<access-denied-handler error-page="/accessDenied" />
<intercept-url pattern="/publicIndex1" access="isAnonymous()"/>
<intercept-url pattern="/index1" access="isAnonymous()"/>
<!-- Restrict URLs based on role -->
<intercept-url pattern="/#/publicIndex" access="isAnonymous()" />
<form-login
login-page="/publicIndex1"
always-use-default-target="false"
default-target-url="/index"
authentication-failure-url="/publicIndex1"
username-parameter="username"
password-parameter="password" />
<logout logout-success-url="/index1"
delete-cookies="JSESSIONID"
logout-url="/logout"
invalidate-session="true" />
</http>
在您的弹簧控制器中。
@RequestMapping(value = "/accessDenied", method = RequestMethod.GET)
public ModelAndView accessDenied() {
System.out.println("access denied page call");
return new ModelAndView("accessDenied");
}
@RequestMapping(value = "/#/publicIndex", method = RequestMethod.GET)
public ModelAndView login(@RequestParam(value = "error", required = false) String error,
@RequestParam(value = "logout", required = false) String logout) {
System.out.println("inside /#/public index");
ModelAndView model = new ModelAndView();
if (error != null) {
model.addObject("error", "Invalid username and password!");
}
System.out.println("**********************" + error);
if (logout != null) {
model.addObject("msg", "You've been logged out successfully.");
}
model.setViewName("publicIndex");
return model;
}
@RequestMapping(value = "/logout", method = RequestMethod.GET)
public String logout1() {
System.out.println();
User user1 = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
return userService.addUserOffline(user1.getUserId());
}
@RequestMapping(value = "/index", method = RequestMethod.GET)
public ModelAndView index() {
System.out.println("Redirect Controller Call");
User user = new User();
try {
user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
} catch (Exception e) {
return new ModelAndView("publicIndex1");
}
long userId = user.getUserId();
userService.addLastLoginDate(userId);
System.out.println("user id==" + userId);
return new ModelAndView("index");
}
@RequestMapping(value = "/index1", method = RequestMethod.GET)
public ModelAndView index1() {
System.out.println("inside logout index1");
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (!(auth instanceof AnonymousAuthenticationToken)) {
return new ModelAndView("/index");
} else {
return new ModelAndView("index1");
}
}