SpringSecurity实现自定义登录接口
1、配置类 ConfigClazz(SpringSecuriey的)
java"> @Resource private DIYUsernamePasswordAuthenticationFilter diyUsernamePasswordAuthenticationFilter; @Bean public SecurityFilterChain filterChain ( HttpSecurity http) throws Exception { http. authorizeRequests ( authorize -> authorize. requestMatchers ( "/user/**" , "/" ) . hasRole ( "user" ) . requestMatchers ( "/manager/**" ) . hasRole ( "manager" ) . requestMatchers ( "/login/**" ) . permitAll ( ) . anyRequest ( ) . authenticated ( ) ) ; http. formLogin ( AbstractHttpConfigurer :: disable ) ; http. logout ( logout -> { logout. logoutUrl ( "/goOut" ) . permitAll ( ) . logoutSuccessHandler ( ( HttpServletRequest request, HttpServletResponse response, Authentication authentication) -> { Map < String , String [ ] > parameterMap = request. getParameterMap ( ) ; if ( ! parameterMap. isEmpty ( ) && parameterMap. get ( "TowLogin" ) [ 0 ] . equals ( "true" ) ) { String json = JSON. toJSONString ( Code. NOTowLogin ) ; response. setContentType ( "application/json;charset=UTF-8" ) ; response. getWriter ( ) . println ( json) ; } else { String json = JSON. toJSONString ( Code. SuccessLogout ) ; response. setContentType ( "application/json;charset=UTF-8" ) ; response. getWriter ( ) . println ( json) ; } } ) ; } ) ; http. addFilterAfter ( diyUsernamePasswordAuthenticationFilter, LogoutFilter . class ) ; http. exceptionHandling ( exception -> { exception. authenticationEntryPoint ( ( HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) -> { String json = JSON. toJSONString ( Code. NoLogin ) ; response. setContentType ( "application/json;charset=UTF-8" ) ; response. getWriter ( ) . println ( json) ; } ) ; exception. accessDeniedHandler ( ( HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) -> { String json = JSON. toJSONString ( Code. Forbidden ) ; response. setContentType ( "application/json;charset=UTF-8" ) ; response. getWriter ( ) . println ( json) ; } ) ; } ) ; http. sessionManagement ( session -> { session. maximumSessions ( 1 ) . expiredSessionStrategy ( ( SessionInformationExpiredEvent event) -> { String json = JSON. toJSONString ( Code. ForeignLogin ) ; HttpServletResponse response = event. getResponse ( ) ; response. setContentType ( "application/json;charset=UTF-8" ) ; response. getWriter ( ) . println ( json) ; } ) ; } ) ; http. cors ( withDefaults ( ) ) ; http. csrf ( AbstractHttpConfigurer :: disable ) ; return http. build ( ) ; } @Bean public BCryptPasswordEncoder bCryptPasswordEncoder ( ) { return new BCryptPasswordEncoder ( 10 ) ; }
解释 _scrf 在哪看,只有最初有,后面就没有,但是如果不携带,就不让你访问接口,因此建议禁用
2、DIYUsernamePasswordAuthenticationFilter
该类用于替换 UsernamePasswordAuthenticationFilter 过滤器,应用自己自定义的过滤器
java">@Component
public class DIYUsernamePasswordAuthenticationFilter extends OncePerRequestFilter { @Override protected void doFilterInternal ( HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException , IOException { Map < String , String [ ] > parameterMap = request. getParameterMap ( ) ; SUser user = null ; HttpSession session = request. getSession ( ) ; if ( parameterMap. get ( "token" ) != null ) user = ( SUser ) session. getAttribute ( parameterMap. get ( "token" ) [ 0 ] ) ; if ( user == null ) { filterChain. doFilter ( request, response) ; return ; } UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken ( user, user. getPassword ( ) , user. getAuthorities ( ) ) ; SecurityContextHolder . getContext ( ) . setAuthentication ( authenticationToken) ; filterChain. doFilter ( request, response) ; }
}
3、DIYAuthenticationProvider
java">@Component
public class DIYAuthenticationProvider implements AuthenticationProvider { @Resource private UserDetailsService userDetailsService; @Resource private PasswordEncoder passwordEncoder; @Override public Authentication authenticate ( Authentication authentication) throws AuthenticationException { String username = authentication. getName ( ) ; String password = ( String ) authentication. getCredentials ( ) ; UserDetails userDetails = userDetailsService. loadUserByUsername ( username) ; if ( ! passwordEncoder. matches ( password, userDetails. getPassword ( ) ) ) { throw new BadCredentialsException ( "用户名或密码错误" ) ; } UsernamePasswordAuthenticationToken authenticatedToken = new UsernamePasswordAuthenticationToken ( userDetails, userDetails. getPassword ( ) , userDetails. getAuthorities ( ) ) ; authenticatedToken. setDetails ( authentication. getDetails ( ) ) ; return authenticatedToken; } @Override public boolean supports ( Class < ? > authentication) { return UsernamePasswordAuthenticationToken . class . isAssignableFrom ( authentication) ; }
}
4、DIYAuthenticationManager
java">@Component
public class DIYAuthenticationManager implements AuthenticationManager { @Resource AuthenticationProvider authenticationProvider; @Override public Authentication authenticate ( Authentication authentication) throws AuthenticationException { return authenticationProvider. authenticate ( authentication) ; }
}
5、MySQLUserDetailsManager
java">@Component
public class MySQLUserDetailsManager implements UserDetailsService { @Resource SUserMapper sUserMapper; @Resource HttpServletRequest request; @Override public UserDetails loadUserByUsername ( String account) throws UsernameNotFoundException { List < SUser > sUsers = sUserMapper. selectAllByEmail ( account) ; if ( sUsers != null && ! sUsers. isEmpty ( ) ) { SUser sUser = sUsers. get ( 0 ) ; HttpSession session = request. getSession ( ) ; session. setAttribute ( String . valueOf ( sUser. getEmail ( ) ) , sUser) ; return sUser; } else { throw new UsernameNotFoundException ( account) ; } }
}
6、控制层
java">@Controller
@Tag ( name = "登录注册" )
@RequestMapping ( "/login" )
public class LoginController { @Resource private SUserService sUserService; @Resource private AuthenticationManager authenticationManager; @GetMapping ( "/getLoginHTML" ) public String getLoginHtml ( HttpSession session) { boolean aNew = session. isNew ( ) ; if ( aNew) return "login" ; return "redirect:/goOut?TowLogin=true" ; } @PostMapping ( "/ooo" ) @ResponseBody public Code login ( String account, String password) { SUser sUser = new SUser ( ) ; sUser. setEmail ( account) ; sUser. setPassword ( password) ; UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken ( sUser, password) ; Authentication authenticate = authenticationManager. authenticate ( authenticationToken) ; if ( Objects . isNull ( authenticate) ) throw new AuthenticationCredentialsNotFoundException ( "用户账号或密码错误" ) ; else { Map < String , String > map = new HashMap < > ( ) ; map. put ( "token" , authenticate. getName ( ) ) ; return new Code < > ( Code . OK, map) ; }
}
7、增强用户的实体类
这里由于要封装用户的详细信息,而用 MybatisX 生成的 User 实体类不能满足需求,因此要实现一个接口
java">@TableName ( value = "s_user" )
@Data
@Repository
public class SUser implements Serializable , UserDetails { @TableId ( type = IdType . AUTO) private Integer id; private String name; private Integer age; private String sex; private String email; private String password; private Integer isForbidden; private String role; @TableLogic private Integer isDelete; @Serial @TableField ( exist = false ) private static final long serialVersionUID = 1L ; @Override public Collection < ? extends GrantedAuthority > getAuthorities ( ) { List < SimpleGrantedAuthority > list = new ArrayList < > ( ) ; list. add ( new SimpleGrantedAuthority ( "ROLE_" + role) ) ; return list; } @Override public String getUsername ( ) { return this . email; } @Override public boolean isAccountNonExpired ( ) { return true ; } @Override public boolean isAccountNonLocked ( ) { return isForbidden == 1 ; } @Override public boolean isCredentialsNonExpired ( ) { return true ; } @Override public boolean isEnabled ( ) { return true ; }
}
7、依赖
java 版本 17springBoot版本 3.2.0
< dependencies> < dependency> < groupId> org.springframework.boot</ groupId> < artifactId> spring-boot-starter</ artifactId> </ dependency> < dependency> < groupId> org.springframework.boot</ groupId> < artifactId> spring-boot-starter-test</ artifactId> < scope> test</ scope> </ dependency> < dependency> < groupId> org.springframework.boot</ groupId> < artifactId> spring-boot-starter-security</ artifactId> </ dependency> < dependency> < groupId> org.springframework.boot</ groupId> < artifactId> spring-boot-starter-thymeleaf</ artifactId> </ dependency> < dependency> < groupId> com.baomidou</ groupId> < artifactId> mybatis-plus-boot-starter</ artifactId> < version> 3.5.4.1</ version> < exclusions> < exclusion> < groupId> org.mybatis</ groupId> < artifactId> mybatis-spring</ artifactId> </ exclusion> </ exclusions> </ dependency> < dependency> < groupId> org.mybatis</ groupId> < artifactId> mybatis-spring</ artifactId> < version> 3.0.3</ version> </ dependency> < dependency> < groupId> mysql</ groupId> < artifactId> mysql-connector-java </ artifactId> < version> 8.0.30</ version> </ dependency> < dependency> < groupId> org.projectlombok</ groupId> < artifactId> lombok</ artifactId> </ dependency> < dependency> < groupId> org.springframework.boot</ groupId> < artifactId> spring-boot-starter-web</ artifactId> </ dependency> < dependency> < groupId> com.alibaba.fastjson2</ groupId> < artifactId> fastjson2</ artifactId> < version> 2.0.37</ version> </ dependency> < dependency> < groupId> com.github.xiaoymin</ groupId> < artifactId> knife4j-openapi3-jakarta-spring-boot-starter</ artifactId> < version> 4.4.0</ version> </ dependency> </ dependencies>