我有一个使用 Spring 安全性的 SpringBoot 应用程序,但我想在身份验证而非授权时对其进行自定义。我已成功登录,但我不知道我必须将注销操作放在哪里。 这是我的一些代码: 1. Controller :
@RequestMapping(value={"/login"}, method=RequestMethod.GET)
public ModelAndView login(){
return new ModelAndView("pages/login");
}
网络安全配置
@Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class WebSecurityConfig extends WebSecurityConfigurerAdapter { private @Autowired CustomAuthenticationProvider authenticationManager; @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest() .authenticated() .and() .formLogin() .usernameParameter("username") .passwordParameter("password") .failureUrl("/login?error") .defaultSuccessUrl("/") .loginPage("/login") .permitAll() .and() .logout() .logoutRequestMatcher( new AntPathRequestMatcher("/login?logout") ).logoutSuccessUrl("/login").permitAll() .and() .csrf().disable(); } @Autowired @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider( authenticationManager ); } @Bean protected AuthenticationProvider getServicesAuthenticationProvider() { //stackoverflow.com/questions/22453550/custom-authentication-provider-not-being-called/22457561#22457561 return new CustomAuthenticationProvider(); } @Override public void configure(WebSecurity web) throws Exception { web.ignoring() .antMatchers("/**/*.css") .antMatchers("/**/*.js") .antMatchers("/**/*.jpg") .antMatchers("/**/*.png") .antMatchers("/**/*.gif") .antMatchers("/resources/**"); } public PasswordEncoder passwordEncoder(){ PasswordEncoder encoder = NoOpPasswordEncoder.getInstance(); return encoder; } }
CustomAuthenticationProvider
@Component public class CustomAuthenticationProvider implements AuthenticationProvider{ private static Logger logger = Logger.getLogger(CustomAuthenticationProvider.class); private @Autowired UAMSLogin uamsLogin; private Map<String, Boolean> userLoggedIn = new HashMap<String, Boolean>(); @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { String username = authentication.getPrincipal() + ""; String password = authentication.getCredentials() + ""; logger.info("authenticating...."); if(username.equals("")|| username==null || password.equals("")|| password==null){ logger.fatal("username or password cannot be empty!"); return null; } else if(userLoggedIn.containsKey(username)){ UsernamePasswordAuthenticationToken a = new UsernamePasswordAuthenticationToken(username, password); return a; } try { if (uamsLogin.loginUams(username, password)) { logger.info("authentication success"); UamsSession sessionInfo = uamsLogin.getUams(); logger.info("authentication success"); String role = "USER"; userLoggedIn.put(username, true); UsernamePasswordAuthenticationToken a = new UsernamePasswordAuthenticationToken(username, password); return a; } } catch (Exception e) { // TODO Auto-generated catch block logger.info("authentication failed"); e.printStackTrace(); throw new BadCredentialsException("1000"); } return null; } @Override public boolean supports(Class<?> authentication) { return authentication.equals(UsernamePasswordAuthenticationToken.class); } }
UAMS 登录:
@Component public class UAMSLogin implements Serializable { private static Logger logger = Logger.getLogger(UAMSLogin.class); private static final long serialVersionUID = 1L; private static boolean isConnected = false; private UamsSession session; @Value("${UAMS.SEC_SRV_CONN}") private String UAMS_SERVER_CONNECTION; @Value("${UAMS.CSM_SERVER_URL}") private String UAMS_CSM_SERVER_URL; @Value("${amdocs.ticketapplicationid}") private String amdocs_ticketapplicationid; @Value("${amdocs.ticketparam}") private String amdocs_ticketparam; public UAMSLogin(){ } // Login with UAMS public boolean loginUams(String username, String password) throws Exception { logger.info("loginUams with " + username + "/" + password); session = this.createSession(); logger.info("create session success: "+session.toString()); String ticket=null; logger.info("UamsSystem version: "+UamsSystem.getVersionString()); try { session.ensureSession(username, password); ticket = session.getTicket(); if (ticket != null && ticket !="") { logger.info("login success : " + session.getTicket()); isConnected = true; return true; } else { logger.info("login failed: ticket is NULL"); return false; } } catch (Exception e) { logger.info("login failed: ", e); return false; } } protected UamsSession createSession() throws Exception { UamsSession session = new UamsSession(ReadConfig.readInputStream()); logger.info("UAMS_SERVER_CONNECTION: "+UAMS_SERVER_CONNECTION); logger.info("UAMS_CSM_SERVER_URL: "+UAMS_CSM_SERVER_URL); logger.info("amdocs_ticketapplicationid: "+amdocs_ticketapplicationid); logger.info("amdocs_ticketparam: "+amdocs_ticketparam); session.setSecurityUrl(UAMS_SERVER_CONNECTION); session.setProviderUrl(UAMS_CSM_SERVER_URL); session.setApplicationId(amdocs_ticketapplicationid); session.setParam(amdocs_ticketparam); return session; } public static boolean isConnected() { return isConnected; } public UamsSession getUams(){ return session; } }
如您所见,我正在使用 UAMS 来查看此用户是否有效。我仍然不知道如何记住每个 session ,所以你可以看到有脏代码 HashMap containsKey
。更重要的是,如果我制作 session.logout(username);
我应该在哪里调用它?
UAMS是我公司用的一个Jar。
如果你觉得这个问题不清楚,我很抱歉,请问我。 任何帮助将不胜感激。
最佳答案
如果我理解,我猜你想在 Spring Security 中完成注销后对你谈到的 UAMS 库执行一些操作。
如果这就是您所说的,我最好使用自定义 LogoutSuccessHandler并将其在您的配置中绑定(bind)到注销操作。
LogoutSuccessHandler 接口(interface)只有一个您应该实现的方法:
public class CustomLogoutHandler implements LogoutSuccessHandler {
private Logger logger = Logger.getLogger(this.getClass());
/* (non-Javadoc)
* @see org.springframework.security.web.authentication.logout.LogoutSuccessHandler#onLogoutSuccess(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, org.springframework.security.core.Authentication)
*/
@Override
public void onLogoutSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
logger.debug("CustomLogoutHandler.onLogoutSuccess");
}
}
在这里您可以做任何您需要的事情,甚至可以在 session 注销后重定向到您应该去的任何页面。
编辑:
你应该像我说的那样使用一个 LogoutSuccessHandler 或者最好添加一个 LogoutHandler :
public class TaskImplementingLogoutHandler implements LogoutHandler {
/* (non-Javadoc)
* @see org.springframework.security.web.authentication.logout.LogoutHandler#logout(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, org.springframework.security.core.Authentication)
*/
@Override
public void logout(HttpServletRequest req, HttpServletResponse res,
Authentication authentication) {
// do whatever you need
}
}
一旦您实现了符合您需要的 LogoutHandler,您应该将它添加到您的配置中。查看 java 安全配置 logout section
您的 java 安全配置必须是这样的:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.formLogin()
.usernameParameter("username")
.passwordParameter("password")
.failureUrl("/login?error")
.defaultSuccessUrl("/")
.loginPage("/login")
.permitAll()
.and()
.logout()
.logoutRequestMatcher(
new AntPathRequestMatcher("/login?logout")
)
.addLogoutHandler(new TaskImplementingLogoutHandler())
.logoutSuccessUrl("/login").permitAll()
.and()
.csrf().disable();
}
关于spring-mvc - Spring Security 自定义注销,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38479878/