SpringSecurity实现自定义登录接口
1、配置类 ConfigClazz(SpringSecuriey的)
java"> @Resourceprivate DIYUsernamePasswordAuthenticationFilter diyUsernamePasswordAuthenticationFilter;@Beanpublic 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();}@Beanpublic BCryptPasswordEncoder bCryptPasswordEncoder(){return new BCryptPasswordEncoder(10); }
- 解释 _scrf 在哪看,只有最初有,后面就没有,但是如果不携带,就不让你访问接口,因此建议禁用
2、DIYUsernamePasswordAuthenticationFilter
- 该类用于替换 UsernamePasswordAuthenticationFilter 过滤器,应用自己自定义的过滤器
java">@Component
public class DIYUsernamePasswordAuthenticationFilter extends OncePerRequestFilter {@Overrideprotected 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 {@Resourceprivate UserDetailsService userDetailsService;@Resourceprivate PasswordEncoder passwordEncoder;@Overridepublic 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;}@Overridepublic 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 {@Resourceprivate SUserService sUserService;@Resourceprivate 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;@TableLogicprivate Integer isDelete;@Serial@TableField(exist = false)private static final long serialVersionUID = 1L;@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {List<SimpleGrantedAuthority> list = new ArrayList<>();list.add(new SimpleGrantedAuthority("ROLE_" + role));return list;}@Override public String getUsername() {return this.email;}@Overridepublic boolean isAccountNonExpired() {return true;}@Overridepublic boolean isAccountNonLocked() {return isForbidden == 1;}@Overridepublic boolean isCredentialsNonExpired() {return true;}@Overridepublic boolean isEnabled() {return true;}
}
7、依赖
- java版本 17
- springBoot版本 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>