Spring 安全无法注销
Spring security cannot logout
我在 Spring 启动应用程序中自定义实现了 Spring 安全性。所以我有我的依赖项,我有一个名为 SecurityImpl 的 class,它为我实现了登录访问。
当我进入浏览器时,系统会正确地要求我使用警报登录。当我登录时,我可以正确访问我的 Spring 控制器的所有 @RequestMapping。但我始终保持登录状态。即使我从浏览器中删除了 JSESSIONID,当我发出另一个 http 请求时,我也被允许并创建一个新的 JSESSIONID 并将其发送到我的浏览器。
奇怪的是,即使我第一次使用登录访问,即使cookie是自动生成的,过期日期也是:1969-12-31T23:59:59.000Z
我尝试过使会话无效、从服务器删除 cookie、以各种方式注销,但都没有。一旦登录,我总是被允许的。
这里是我的 SecurityImpl.java class,它配置了我的 Spring 安全性:
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
@Configuration
@Component
public class SecurityImpl extends WebSecurityConfigurerAdapter implements AuthenticationProvider {
public static final String ROLE_ADMIN = "ROLE_ADMIN";
public static final String ROLE_USER = "ROLE_USER";
@Autowired UtenteDao utenteDao;
/* authentication provider part */
@Override
public Authentication authenticate(Authentication auth) throws AuthenticationException {
String username = auth.getName();
String password = auth.getCredentials().toString();
String ruolo = "";
Optional<Utente> utenteOptional = utenteDao.findByCodiceFiscaleAndPassword(username, password);
if(utenteOptional.isPresent()){
ruolo = utenteOptional.get().getRuolo();
}
if(ROLE_ADMIN.equals(ruolo)) {
List<GrantedAuthority> grantedAuths = new ArrayList<>();
grantedAuths.add(new SimpleGrantedAuthority(ROLE_USER));
grantedAuths.add(new SimpleGrantedAuthority(ROLE_ADMIN));
return new UsernamePasswordAuthenticationToken(username, password, grantedAuths);
} else if(ROLE_USER.equals(ruolo)){
List<GrantedAuthority> grantedAuths = new ArrayList<>();
grantedAuths.add(new SimpleGrantedAuthority(ROLE_USER));
return new UsernamePasswordAuthenticationToken(username, password, grantedAuths);
} else {
throw new BadCredentialsException("Autenticazione fallita");
}
}
@Override
public boolean supports(Class<?> auth) {
return auth.equals(UsernamePasswordAuthenticationToken.class);
}
/* websecurity adapter part: erase it if you don't want login alert but default spring login web page */
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(this); //this because it is either a WebSecurityAdapter than an AuthenticationProvider
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated()
.and()
.httpBasic()
.and()
.logout().clearAuthentication(true).logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/test")
.deleteCookies("JSESSIONID")
.invalidateHttpSession(true);
}
/* per non filtrare con il login alcuni path */
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/test");
}
}
它不起作用:当我转到 /logout 时,我被正确地重定向到 /test,但是当我请求禁止的路径时,我被允许无需任何登录。
然后我在我的@RestController 中尝试了一些解决方案:
@RequestMapping("/logout")
public String logoutPage (UsernamePasswordAuthenticationToken token) {
token.eraseCredentials();
token.setAuthenticated(false);
SecurityContextHolder.getContext().setAuthentication(null);
return "<h1>Logout effettuato con successo.</h1>";
}
然后我尝试了:
@RequestMapping(value = "/logout")
public String loadApp(HttpServletRequest request) {
HttpSession session= request.getSession(false);
SecurityContextHolder.clearContext();
if(session != null) {
session.invalidate();
}
return "<h1>Logout effettuato con successo.</h1>";
}
然后,作为一个绝望的人,我尝试了:
@RequestMapping("/logout")
public String logoutDo(HttpServletRequest request){
HttpSession session= request.getSession(false);
SecurityContextHolder.clearContext();
session= request.getSession(false);
if(session != null) {
session.invalidate();
}
for(Cookie cookie : request.getCookies()) {
cookie.setMaxAge(0);
}
return "<h1>Logout effettuato con successo.</h1>";
}
我尝试使用这些方法并同时从浏览器中删除了我的 cookie。我还尝试使用注释@PreAuthorize 预授权被禁止的方法,以防它们被允许(当你打开一个新的浏览器,在第一次登录之前,即使没有@PreAuthorize,它们也是不允许的,但是当登录时,IS永远!)
问题是没有使用 showForm()。没有它,是的,我将我的凭据插入呈现给我的 Javascript 警报中。但是无法注销。
所以代码改成这样:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.httpBasic()
.and()
.logout().clearAuthentication(true).logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/test")
.deleteCookies("JSESSIONID")
.invalidateHttpSession(true);
}
我在 Spring 启动应用程序中自定义实现了 Spring 安全性。所以我有我的依赖项,我有一个名为 SecurityImpl 的 class,它为我实现了登录访问。 当我进入浏览器时,系统会正确地要求我使用警报登录。当我登录时,我可以正确访问我的 Spring 控制器的所有 @RequestMapping。但我始终保持登录状态。即使我从浏览器中删除了 JSESSIONID,当我发出另一个 http 请求时,我也被允许并创建一个新的 JSESSIONID 并将其发送到我的浏览器。
奇怪的是,即使我第一次使用登录访问,即使cookie是自动生成的,过期日期也是:1969-12-31T23:59:59.000Z
我尝试过使会话无效、从服务器删除 cookie、以各种方式注销,但都没有。一旦登录,我总是被允许的。
这里是我的 SecurityImpl.java class,它配置了我的 Spring 安全性:
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
@Configuration
@Component
public class SecurityImpl extends WebSecurityConfigurerAdapter implements AuthenticationProvider {
public static final String ROLE_ADMIN = "ROLE_ADMIN";
public static final String ROLE_USER = "ROLE_USER";
@Autowired UtenteDao utenteDao;
/* authentication provider part */
@Override
public Authentication authenticate(Authentication auth) throws AuthenticationException {
String username = auth.getName();
String password = auth.getCredentials().toString();
String ruolo = "";
Optional<Utente> utenteOptional = utenteDao.findByCodiceFiscaleAndPassword(username, password);
if(utenteOptional.isPresent()){
ruolo = utenteOptional.get().getRuolo();
}
if(ROLE_ADMIN.equals(ruolo)) {
List<GrantedAuthority> grantedAuths = new ArrayList<>();
grantedAuths.add(new SimpleGrantedAuthority(ROLE_USER));
grantedAuths.add(new SimpleGrantedAuthority(ROLE_ADMIN));
return new UsernamePasswordAuthenticationToken(username, password, grantedAuths);
} else if(ROLE_USER.equals(ruolo)){
List<GrantedAuthority> grantedAuths = new ArrayList<>();
grantedAuths.add(new SimpleGrantedAuthority(ROLE_USER));
return new UsernamePasswordAuthenticationToken(username, password, grantedAuths);
} else {
throw new BadCredentialsException("Autenticazione fallita");
}
}
@Override
public boolean supports(Class<?> auth) {
return auth.equals(UsernamePasswordAuthenticationToken.class);
}
/* websecurity adapter part: erase it if you don't want login alert but default spring login web page */
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(this); //this because it is either a WebSecurityAdapter than an AuthenticationProvider
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated()
.and()
.httpBasic()
.and()
.logout().clearAuthentication(true).logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/test")
.deleteCookies("JSESSIONID")
.invalidateHttpSession(true);
}
/* per non filtrare con il login alcuni path */
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/test");
}
}
它不起作用:当我转到 /logout 时,我被正确地重定向到 /test,但是当我请求禁止的路径时,我被允许无需任何登录。
然后我在我的@RestController 中尝试了一些解决方案:
@RequestMapping("/logout")
public String logoutPage (UsernamePasswordAuthenticationToken token) {
token.eraseCredentials();
token.setAuthenticated(false);
SecurityContextHolder.getContext().setAuthentication(null);
return "<h1>Logout effettuato con successo.</h1>";
}
然后我尝试了:
@RequestMapping(value = "/logout")
public String loadApp(HttpServletRequest request) {
HttpSession session= request.getSession(false);
SecurityContextHolder.clearContext();
if(session != null) {
session.invalidate();
}
return "<h1>Logout effettuato con successo.</h1>";
}
然后,作为一个绝望的人,我尝试了:
@RequestMapping("/logout")
public String logoutDo(HttpServletRequest request){
HttpSession session= request.getSession(false);
SecurityContextHolder.clearContext();
session= request.getSession(false);
if(session != null) {
session.invalidate();
}
for(Cookie cookie : request.getCookies()) {
cookie.setMaxAge(0);
}
return "<h1>Logout effettuato con successo.</h1>";
}
我尝试使用这些方法并同时从浏览器中删除了我的 cookie。我还尝试使用注释@PreAuthorize 预授权被禁止的方法,以防它们被允许(当你打开一个新的浏览器,在第一次登录之前,即使没有@PreAuthorize,它们也是不允许的,但是当登录时,IS永远!)
问题是没有使用 showForm()。没有它,是的,我将我的凭据插入呈现给我的 Javascript 警报中。但是无法注销。
所以代码改成这样:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.httpBasic()
.and()
.logout().clearAuthentication(true).logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/test")
.deleteCookies("JSESSIONID")
.invalidateHttpSession(true);
}