demo git address: Portal
First: Preface
Now most of them are front-end and back-end projects. In hard coding, jumping to a page path is obviously inappropriate, so the server should return to JSON. To inform the front-end whether to log in, whether to have page permissions, whether to log in overtime, etc., according to the return of JSON agreed value, the front-end from the free jump.
Second: concrete realization
1. Setting up state configuration classes such as successful login, failure, no privilege, etc.
Access Denied Handler Config
@Component public class AccessDeniedHandlerConfig implements AccessDeniedHandler { @Override public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException { JSONObject result = new JSONObject(); result.put("msg","No permission!"); httpServletResponse.setContentType("application/json;charset=utf-8"); httpServletResponse.getWriter().println(result.toJSONString()); } }
Authentication Entry Point Config (not logged in)
@Component public class AuthenticationEntryPointConfig implements AuthenticationEntryPoint { @Override public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException { JSONObject json = new JSONObject(); json.put("msg","Not logged in"); httpServletResponse.setContentType("application/json;charset=utf-8"); httpServletResponse.getWriter().write("null"); } }
Authentication Failure Handler Config
@Component public class AuthenticationFailureHandlerConfig implements AuthenticationFailureHandler { @Override public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException { JSONObject json = new JSONObject(); json.put("msg","Logon failure"); httpServletResponse.setContentType("application/json;charset=utf-8"); httpServletResponse.getWriter().write(json.toJSONString()); } }
Authentication Success Handler Config
@Component public class AuthenticationSuccessHandlerConfig implements AuthenticationSuccessHandler { @Override public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException { JSONObject json = new JSONObject(); json.put("msg","Successful login"); httpServletResponse.setContentType("application/json;charset=utf-8"); httpServletResponse.getWriter().write(json.toJSONString()); } }
Logout Handler Config
@Component public class LogoutHandlerConfig implements LogoutHandler { @Override public void logout(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) { try { String url = httpServletRequest.getParameter("redirectUrl"); //Implementing custom redirection httpServletResponse.sendRedirect(url); }catch (IOException e){ } } }
Logout path: localhost:8080/logout
redirectUrl is a custom jump url address for the front end, otherwise it will automatically jump to the default security address after logout, such as:
Logout Success Handler Config (Logout Successful Configuration)
@Component public class LogoutSuccessHandlerConfig implements LogoutSuccessHandler { @Override public void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException { JSONObject result = new JSONObject(); result.put("msg","Cancellation!"); httpServletResponse.setContentType("application/json;charset=utf-8"); httpServletResponse.getWriter().write(result.toJSONString()); } }
2. model preparation
SysUser,SysRole,SysUserRole
@Data public class SysUser implements Serializable { private String userId; private String userName; private String password; private String updateUserId; private String createUserId; private LocalDateTime updateTime; private LocalDateTime createTime; } @Data public class SysRole implements Serializable { private String roleId; private String name; private Integer state; private String updateUserId; private String createUserId; private LocalDateTime updateTime; private LocalDateTime createTime; } @Data public class SysUserRole implements Serializable { private String userRoleId; private String roleId; private String userId; private String updateUserId; private String createUserId; private LocalDateTime updateTime; private LocalDateTime createTime; }
Principle of Custom Verification Mechanism
User Name Password - > (Authentication (Unauthenticated) - > AuthenticationManager -> AuthenticationProvider -> UserDetailService - > UserDetails - > Authentication (certified) passed
3. Define User Object, Implement User Details Service, SelfAuthentication Provider Class
Create SelfUserDetails
@Data public class SelfUserDetails implements UserDetails, Serializable { private String username; private String password; private Set<? extends GrantedAuthority> authorities; @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return true; } }
Create SelfUser Details Service to implement User Details Service
@Service public class SelfUserDetailsService implements UserDetailsService { @Autowired SysUserService sysUserService; @Override public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException { SelfUserDetails userInfo = new SelfUserDetails(); userInfo.setUsername(userName); SysUser sysUser = sysUserService.getUserByUsername(userName); if (sysUser == null) { throw new UsernameNotFoundException("Users do not exist!"); } userInfo.setPassword(sysUser.getPassword()); SysRole sysRole = sysUserService.getUserRoleInfo(sysUser.getUserId()); if (sysRole == null) { throw new UsernameNotFoundException("Users are not allotted permissions!"); } if (sysRole.getState() == 0) { throw new UsernameNotFoundException("User privileges are invalid!"); } userInfo.setAuthorities(getAuthorities(sysRole.getName())); return userInfo; } private Set<GrantedAuthority> getAuthorities(String role) { Set<GrantedAuthority> authoritiesSet = new HashSet(); GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(role); authoritiesSet.add(grantedAuthority); return authoritiesSet; } }
Create the SelfAuthentication Provider class to implement Authentication Provider
public class SelfAuthenticationProvider implements AuthenticationProvider { @Autowired SelfUserDetailsService userDetailsService; @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { String userName = (String) authentication.getPrincipal(); String password = (String) authentication.getCredentials(); BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder(); String encodePwd = bCryptPasswordEncoder.encode(password); UserDetails userInfo = userDetailsService.loadUserByUsername(userName); if (userInfo == null) { throw new UsernameNotFoundException("user does not exist"); } if(!userInfo.getPassword().equals(encodePwd)) { throw new BadCredentialsException("Password error"); } return new UsernamePasswordAuthenticationToken(userName, password, userInfo.getAuthorities()); } @Override public boolean supports(Class<?> authentication) { return UsernamePasswordAuthenticationToken.class.equals(authentication); } }
4. Privilege Configuration Class
Create RbacService (role-Based-access control) permission control, url permission part is not implemented, interested partners can work together to improve.
@Service("rbacService") public class RbacServiceImpl implements RbacService { private AntPathMatcher antPathMatcher = new AntPathMatcher(); @Override public boolean hasPermission(HttpServletRequest request, Authentication authentication) { String userName = (String) authentication.getPrincipal(); //Read whether the current user has url privileges //todo not implemented if (antPathMatcher.match("", request.getRequestURI())) { return true; } return false; } }
5. Configuring security
Create the Security Config configuration class, configure the core:
@Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .httpBasic().authenticationEntryPoint(authenticationEntryPoint) .and() .authorizeRequests() .antMatchers("/role/**").hasRole("admin") // This means that / index is a page that does not require authorization and is accessible to everyone. /* .antMatchers("/test/**").permitAll() .antMatchers(HttpMethod.POST,"/user/").hasRole("ADMIN") .antMatchers(HttpMethod.GET,"/user/").hasRole("USER") .antMatchers("/role/**").hasRole("admin") .anyRequest().authenticated()*/ .anyRequest().access("@rbacService.hasPermission(request,authentication)") //.anyRequest().access("") // Other URLs require authentication //.authenticated() .and() // login correlation // Open Logon .formLogin() // Successful login .successHandler(authenticationSuccessHandler) // Logon failure .failureHandler(authenticationFailureHandler) .permitAll() .and() // logout correlation .logout() .logoutSuccessHandler(logoutSuccessHandler) .addLogoutHandler(logoutHandler) .permitAll().and() // Remembering that I am relevant .rememberMe() .rememberMeParameter("remember-me").userDetailsService(selfUserDetailsService) .tokenRepository(persistentTokenRepository()) .tokenValiditySeconds(6000); // No access to data in JSON format http.exceptionHandling().accessDeniedHandler(accessDeniedHandler); }
Now the function is basically available, just need to improve the status of each return result can be used.
6. Remember me, remember my function Remeber me
@Autowired DataSource dataSource; @Bean public PersistentTokenRepository persistentTokenRepository() { JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl(); tokenRepository.setDataSource(dataSource); return tokenRepository; }
Add in config
.rememberMe() .rememberMeParameter("remember-me").userDetailsService(selfUserDetailsService) .tokenRepository(persistentTokenRepository())
demo git address: Portal
Welcome to review, improve and supplement, point out the shortcomings, thank you.