- Connectionless
- When a client and server exchange a request and a response once, disconnect.
- Stateless
- After communication, not stay state information
- So, due to these characteristics, can stay information of user authentication, using Session&Cookie or jwt.
- Session&Cookie
- JWT(Json Web Token) token
- OAuth(Open Authentication)
- Principal : Target to access to protected resource.
- Authentication : Process to check who access protected resource and subject being able to conduct tasks. => who?
- Authorization : After authentication, process to check which resources principal can access. => what authorities does principal have?
- Credential : Principal's password accessing resource.
- Conducting based on Filter apart from MVC.
- Basically, authentication through session and cookie
- Managing resource access through Authentication Manager(Authentication) and Access Decision Manager(Authorization).
- Authentication Manager is conducted by UsernamePasswordAuthenticationFilter.
- Access Decision Manager is conducted by FilterSecurityInterceptor.
- Authentication -> After Authentication succeeds -> Authorization
- Authentication information basically stores at in-memory session storage(SecurityContextHolder) as session-cookie way.
- Basically, if request about authentication based on ID, PASSWORD comes about, it reaches UsernamePasswordAuthenticationFilter of Authentication Filters. * If not ID, PASSWORD, but OAuth2.0 or JWT is used, other filter is used. (ex : OAuth2ClientAuthenticationProcessingFilter)
- If the request reaches UsernamePasswordAuthenticationFilter, attemptAuthentication(request,response) method works. This method creates UsernamePasswordAuthenticationToken(Authentication) by bringing username and password from the request.
- AuthenticationManager(ProviderManager) authorize by using UsernamePasswordAuthentciationToken(Authentication)
-
Add dependency
compile('org.springframework.boot:spring-boot-starter-security')
-
Java Configuration
@EnableWebSecurity // Automatically, contain SpringSecurityFilterChain public class SecurityConfig extends WebSecurityConfigurerAdapter{ ... @Override protected void configure(HttpSecurity http) throws Exception { String[] permmited = { "/api/user/signUp","/" }; // Setting cors, csrf http.cors().and().csrf().disable(); // Setting permission of end point and authorize http.authorizeRequests() .antMatchers(permmited).permitAll() .antMatchers("/professor").hasRole("PROFESSOR") .antMatchers("/student").hasAnyRole("STUDENT","PROFESSOR") .and() .formLogin() .loginPage("/") .defaultSuccessUrl("/student") .usernameParameter("userID") // Coincide loginform name .and() .logout() .logoutSuccessUrl("/") .invalidateHttpSession(true) .deleteCookies("JSESSIONID") .and() .exceptionHandling() .accessDeniedPage("/accessDenied"); // Session management http.sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.ALWAYS) .sessionFixation() .changeSessionId() .maximumSessions(1) .maxSessionsPreventsLogin(false) .expiredUrl("/") .sessionRegistry(sessionRegistry()) .and() .invalidSessionUrl("/"); } @Bean public SessionRegistry sessionRegistry() { return new SessionRegistryImpl(); } }
sessionCreationPolicy(SessionCreationPolicy.ALWAYS)
=> Setting session creation policy- SessionCreationPolicy.ALWAYS => Always create session
- SessionCreationPolicy.IF_REQUIRED => (Basic)Create when be required
- SessionCreationPolicy.NEVER => Not create, but if session is existed, use it
- SessionCreationPolicy.STATELESS => Not create, use existed session(JWT)
sessionFixation()
=> Setting about session-fixation attack- changeSessionId() => Issue new sessionId, and capable of using prior session
- newSession() => Issue new sessionId, and not capable of using prior session
- none() => Nothing
maximumSessions(1)
=> Restrict maximum sessionmaxSessionsPreventsLogin(false)
- True => Later user's session is blocked
- If don't normally logout and close browser, occur anyone doesn't login
- False => Prior user's session is expired
- True => Later user's session is blocked
expiredUrl("/")
=> Url when dupliciate loginsessionRegistry(sessionRegistry())
- If not add sessionRegistry(sessionRegistry()), when user login again after logout, occur error "Maximum sessions of 1 for this principal exceeded".
invalidSessionUrl("/")
=> Url when session is expired
-
Implementation UserDetails
public class User implements UserDetails { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String username; private String password; @Column(name = "role") @Enumerated(EnumType.STRING) private Role role; @Override public String getPassword() { return password; } @Override public String getUsername() { return username; } // Return Authority lists user has @Override public Collection<? extends GrantedAuthority> getAuthorities() { ArrayList<GrantedAuthority> auth = new ArrayList<>(); auth.add(new SimpleGrantedAuthority(role.toString())); return auth; } @Override public boolean isEnabled() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } }
-
Implementation UserDetailsService
@Service public class UserService implements UserDetailsService{ ... @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userRepository.findByUsername(username); if(user != null) return user; else throw new UsernameNotFoundException(username); } }