[SPRING] 여분의 로그인 파라미터를 가진 봄 기억 나
SPRING여분의 로그인 파라미터를 가진 봄 기억 나
봄 mvc 응용 프로그램에서 로그인 화면에서 추가 '위치'매개 변수를 캡처하고 사용자 이름 이외에 인증을 위해 사용하고 있습니다. 그래서 'loadUserByUsername'내 SQL 쿼리는 다음과 같습니다.
select from user where username = ? and location = ?
이제 사용자가 remember-me 사용자 인 경우 로그인 프롬프트가 없으므로 'location'매개 변수를 캡처 할 수있는 방법이 없습니다. remember-me 기능을 사용하는 스프링의 경우 사용자 이름 만 쿠키에 저장합니다. 그리고 remember-me 로그인을 위해 쿠키에서 사용자 이름을 가져 와서 'loadUserByUsername'호출에 전달하여 DB에서 사용자를로드합니다. 그래서, 내 경우에는 remember-me 사용자를 위해 'location'이 null 쿼리가 사용자를로드하는 데 실패하기 때문에 실패합니다. 기본 스프링 동작을 무시하고 사용자 이름과 함께 쿠키에 'location'을 저장 한 다음 PersistentTokenBasedRememberMeServices.processAutoLoginCookie ()에서 'loadUserByUsername'에 위치 및 사용자 이름을 전달하는 방법이 있는지 알고 싶습니다. 참조를 위해 아래 코드를 참고하십시오.
CustomAuthenticationFilter.java :-
public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
final Long locationId = Long.parseLong(request.getParameter("locations"));
request.getSession().setAttribute("LOCATION_ID", locationId);
return super.attemptAuthentication(request, response);
}
}
SecurityConfig.java:-
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
DataSource dataSource;
@Autowired
private AuthenticationManagerBuilder auth;
@Autowired
public void configureGlobal(UserDetailsService userDetailsService, AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Autowired
AccessDeniedExceptionHandler accessDeniedExceptionHandler;
@Bean
public CustomInvalidSessionStrategy invalidSessionStrategy() {
return new CustomInvalidSessionStrategy();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/resources/**").permitAll()
.antMatchers("/error/**").permitAll()
.antMatchers("/secured/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
// .defaultSuccessUrl("/")
.permitAll()
.and().rememberMe().rememberMeServices(persistentTokenBasedRememberMeServices())
.and()
.logout()
.permitAll()
.and()
.exceptionHandling()
.accessDeniedHandler(accessDeniedExceptionHandler);
http.addFilterBefore(customAuthenticationFilter(),
UsernamePasswordAuthenticationFilter.class);
http.addFilterAfter(rememberMeAuthenticationFilter(),
UsernamePasswordAuthenticationFilter.class);
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() {
AuthenticationManager manager = null;
try {
manager = super.authenticationManagerBean();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return manager;
}
@Bean
public SimpleUrlAuthenticationSuccessHandler simpleUrlAuthenticationSuccessHandler() {
SimpleUrlAuthenticationSuccessHandler handler = new SimpleUrlAuthenticationSuccessHandler();
handler.setDefaultTargetUrl("/");
return handler;
}
@Bean
public SimpleUrlAuthenticationFailureHandler simpleUrlAuthenticationFailureHandler() {
SimpleUrlAuthenticationFailureHandler handler = new SimpleUrlAuthenticationFailureHandler();
handler.setDefaultFailureUrl("/login?error");
return handler;
}
@Bean
public CustomAuthenticationFilter customAuthenticationFilter () {
CustomAuthenticationFilter filter= new CustomAuthenticationFilter();
filter.setRequiresAuthenticationRequestMatcher(
new AntPathRequestMatcher("/login","POST"));
filter.setAuthenticationManager(authenticationManagerBean());
filter.setUsernameParameter("username");
filter.setPasswordParameter("password");
filter.setAuthenticationSuccessHandler(simpleUrlAuthenticationSuccessHandler());
filter.setAuthenticationFailureHandler(simpleUrlAuthenticationFailureHandler());
filter.setRememberMeServices(persistentTokenBasedRememberMeServices());
return filter;
}
@Bean
public RememberMeAuthenticationFilter rememberMeAuthenticationFilter() {
RememberMeAuthenticationFilter filter = new RememberMeAuthenticationFilter();
filter.setAuthenticationManager(authenticationManagerBean());
filter.setRememberMeServices(persistentTokenBasedRememberMeServices());
return filter;
}
@Bean
public PersistentTokenBasedRememberMeServices persistentTokenBasedRememberMeServices() {
PersistentTokenBasedRememberMeServices service = new PersistentTokenBasedRememberMeServices("remember_me_key", userDetailsService, persistentTokenRepository());
service.setCookieName("remember_me");
service.setTokenValiditySeconds(864000);
return service;
}
@Autowired
public UserDetailsService userDetailsService;
@Bean
public PersistentTokenRepository persistentTokenRepository() {
JdbcTokenRepositoryImpl tokenRepositoryImpl = new JdbcTokenRepositoryImpl();
tokenRepositoryImpl.setDataSource(dataSource);
return tokenRepositoryImpl;
}
}
해결법
-
==============================
1.기본 스프링 동작을 재정의하고 쿠키에 추가 매개 변수를 저장하려면 Spring의 인터페이스 인 UserDetails를 구현해야합니다. 어떻게하는지 예제가 있습니다.
기본 스프링 동작을 재정의하고 쿠키에 추가 매개 변수를 저장하려면 Spring의 인터페이스 인 UserDetails를 구현해야합니다. 어떻게하는지 예제가 있습니다.
package example.userdetails; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import java.util.Collection; public class CustomUserDetails implements UserDetails { private long id; private String firstName; private String lastName; private String login; private String password; private boolean isAccountNonExpired; private boolean isAccountNonLocked; private boolean isCredentialsNonExpired; private boolean isEnabled; private Collection<? extends GrantedAuthority> authorities; public CustomUserDetails(long id, String firstName, String lastName, String login, String password, boolean isEnabled, Collection<? extends GrantedAuthority> authorities) { this.id = id; this.firstName = firstName; this.lastName = lastName; this.login = login; this.password = password; this.authorities = authorities; this.isEnabled = isEnabled; this.isCredentialsNonExpired = true; this.isAccountNonLocked = true; this.isAccountNonExpired = true; } public long getId() { return id; } public String getFirstName() { return firstName; } public String getLastName() { return lastName; } @Override public Collection<? extends GrantedAuthority> getAuthorities() { return authorities; } @Override public String getPassword() { return password; } @Override public String getUsername() { return login; } @Override public boolean isAccountNonExpired() { return isAccountNonExpired; } @Override public boolean isAccountNonLocked() { return isAccountNonLocked; } @Override public boolean isCredentialsNonExpired() { return isCredentialsNonExpired; } @Override public boolean isEnabled() { return isEnabled; } public boolean hasRole(String role) { for (GrantedAuthority grantedAuthority : authorities) { if (grantedAuthority.getAuthority().equals(role)) { return true; } } return false; } }
로그인 한 사용자를 얻으려면 사용할 수 있습니다.
CustomUserDetails userDetails = (CustomUserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
그리고 loadUserByUsername을 사용하려면 UserDetailsService 인터페이스를 구현해야합니다. 예를 들어
@Service public class UserDetailsServiceImpl implements UserDetailsService { @Autowired private UserDAO userDAO; @Override @Transactional public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException { User user = userDAO.getUserByLogin(userName); if (user == null) { throw new UsernameNotFoundException("Wrong login"); } List<GrantedAuthority> authorities = buildUserAuthority(user.getRoles()); return new CustomUserDetails(user.getUserId(), user.getFirstName(), user.getLastName(), user.getLogin(), user.getPassword(), authorities); } private List<GrantedAuthority> buildUserAuthority(Set<Role> roles) { Set<GrantedAuthority> authoritySet = roles.stream().map(role -> new SimpleGrantedAuthority(buildRoleForAuthorization(role.getRole()))).collect(Collectors.toSet()); return new ArrayList<>(authoritySet); } }
-
==============================
2.PersistentTokenBasedRememberMeServices 클래스를 확장하고 그 메소드를 다음과 같이 재정의하십시오.
PersistentTokenBasedRememberMeServices 클래스를 확장하고 그 메소드를 다음과 같이 재정의하십시오.
@Override processAutoLoginCookie(String[] cookieTokens,HttpServletRequest request, HttpServletResponse response){ super.processAutoLoginCookie(cookieTokens,request,response); // do not provide any implementation to loadUserByUsername() in your CustomUserDetail and add one more method loadUserbyUsenameAndLocation(username, location); String location = request.getSession().getAttribute("LOCATION_ID"); return ((customeUserDetailsService)userDetailsService).loadUserbyUsenameAndLocation(username, location) }
from https://stackoverflow.com/questions/35570818/spring-remember-me-with-extra-login-parameter by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] JPA 엔티티 리스너에 대한 스프링 종속성 주입 (0) | 2019.05.05 |
---|---|
[SPRING] MVC 템플릿 프로젝트의 pom.xml 오류 (0) | 2019.05.05 |
[SPRING] 이미지를 BLOB로 저장할 때 JSP로 텍스트를 표시하는 방법은 무엇입니까? (0) | 2019.05.05 |
[SPRING] 원인 : java.sql.SQLIntegrityConstraintViolationException : 키 'PRIMARY'에 대해 중복 항목 '10'- 스프링 배치 (0) | 2019.05.05 |
[SPRING] 커스텀 userdetailsservice를위한 bean 정의하기 (0) | 2019.05.05 |