# boot_mybatisplus_security_oauth2 **Repository Path**: HesenjanJava/boot_mybatisplus_security_oauth2 ## Basic Information - **Project Name**: boot_mybatisplus_security_oauth2 - **Description**: springboot+spring-security+oauth2+mybatisplus项目,支持请求权限验证,数据库动态权限和请求管理 - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 3 - **Created**: 2022-01-24 - **Last Updated**: 2022-01-24 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # boot_mybatisplus_security_oauth2 #### 介绍 springboot+spring-security+oauth2+mybatisplus项目,支持请求权限验证,数据库动态权限和请求管理 #### 使用说明 如果仅不需要oauth2项目的话可以访问https://gitee.com/luzhizero/springboot_mybatisplus_springsecurity 本项目采用的是最基础的user,role,menu表的结构,可以根据实际业务需求拓展字段 1. 从项目中获取sql ![输入图片说明](https://images.gitee.com/uploads/images/2020/0807/165239_83058bfa_5496301.png "屏幕截图.png") 2. 修改application-local.yml中的redis,mysql配置 ###框架搭建说明 springboot+mybatis项目配置不在此做说明 **1. 配置spring-security ** 添加如下依赖 ``` org.springframework.boot spring-boot-starter-security ``` **2. 基于数据库配置用户名以及密码** 1. 创建一个UserDetails的实现对象,这里采用的如下 - enabled:当前账户是否可用, - accountNonExpired:当前账户是否未过期, - accountNonLocked:当前账户是否未锁定, - credentialsNonExpired:当前账户密码是否未过期,可以在或许进行配置,这里就不展开讲了 ``` @Data @Builder public class SecurityUserDetails implements UserDetails { private String id; private String username; private String password; private String phone; private List roles; private boolean enabled; private boolean accountNonExpired; private boolean accountNonLocked; private boolean credentialsNonExpired; @Override public Collection getAuthorities() { List authorities = new ArrayList<>(); for (Role role : roles) { authorities.add(new SimpleGrantedAuthority(role.getRoleName())); } return authorities; } @Override public String getPassword() { return this.password; } @Override public String getUsername() { return this.username; } @Override public boolean isAccountNonExpired() { return this.accountNonExpired; } @Override public boolean isAccountNonLocked() { return this.accountNonLocked; } @Override public boolean isCredentialsNonExpired() { return this.credentialsNonExpired; } @Override public boolean isEnabled() { return this.enabled; } } ``` 2. 创建一个UserDetails的实现对象,这里采用的如下 ![输入图片说明](https://images.gitee.com/uploads/images/2020/0807/170844_a9cb2b45_5496301.png "屏幕截图.png") 通过继承抽象类来继承UserDetailsService,你也可以直接用实现类来进行操作,直接进行的操作代码如下 ``` @Service public class MyUsernameDetailsService implements UserDetailsService { @Resource private UserService userService; @Resource private RoleService roleService; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = null; try { //获取用户信息 user = userService.getEmpByUsername(username); } catch (Exception e) { e.printStackTrace(); throw new UsernameNotFoundException("查询用户失败,原因是:" + e.getMessage() ); } //获取用户角色信息 List roleList = roleService.getRoleListByUser(user); // 构造security用户 return SecurityUserDetails.builder() .id(user.getId()) .username(user.getAccount()) .password(user.getPassword()) .phone(user.getPhone()) .enabled(true) .accountNonExpired(true) .credentialsNonExpired(true) .accountNonLocked(true) .roles(roleList) .build(); } } ``` 3. 配置 Spring Security ``` @Configuration public class MyWebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired MyUsernameDetailsService myUsernameDetailsService; // 指定密码的加密方式 @SuppressWarnings("deprecation") @Bean PasswordEncoder passwordEncoder(){ // 不对密码进行加密 return NoOpPasswordEncoder.getInstance(); } // 配置用户及其对应的角色 @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(myUsernameDetailsService); } // 配置 URL 访问权限 @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() // 开启 HttpSecurity 配置 .anyRequest().authenticated() // 用户访问其它URL都必须认证后访问(登录后访问) .and().formLogin().loginProcessingUrl("/login").permitAll() // 开启表单登录并配置登录接口 .and().csrf().disable(); // 关闭csrf } } ``` **3. 自定义登录接口,登录成功认证器,登录失败认证器,可支持json** 1.AbstractAuthenticationToken的token类来存得到的第三方的token参数。 ![输入图片说明](https://images.gitee.com/uploads/images/2020/0807/172929_a357f3a7_5496301.png "屏幕截图.png") 2.我们需要一个AbstractAuthenticationProcessingFilter的实现类了来完成自定义登录的权限拦截器 ``` /** * @Description:自定义登录权限拦截器 **/ public class CustomLoginAuthenticationFilter extends AbstractAuthenticationProcessingFilter { public boolean postOnly = true; //在这里配置请求类型以及接口 public CustomLoginAuthenticationFilter() { super(new AntPathRequestMatcher("/user/login", "POST")); } @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { //接口类型判断 if (postOnly && !request.getMethod().equals("POST")) { throw new AuthenticationServiceException( "Authentication method not supported: " + request.getMethod()); } // 授权请求 AbstractAuthenticationToken authRequest; // 用户 String principal; // 凭据 String credentials; // 登录判断 //如果多种登录方式可以在这里添加条件判断,比如前端传过来的是type是phone或者username,通过这些type来走不同的AbstractAuthenticationToken principal = obtainParameter(request, "username"); credentials = obtainParameter(request, "password"); principal = principal.trim(); authRequest = new MyAuthenticationToken(principal, credentials); // 允许子类设置“details”属性 setDetails(request, authRequest); AuthenticationManager authenticationManager = this.getAuthenticationManager(); Authentication authenticate = authenticationManager.authenticate(authRequest); return authenticate; } private void setDetails(HttpServletRequest request, AbstractAuthenticationToken authRequest) { authRequest.setDetails(authenticationDetailsSource.buildDetails(request)); } private String obtainParameter(HttpServletRequest request, String parameter) { String result = request.getParameter(parameter); return result == null ? "" : result; } } ``` 3.自定义登录成功处理类, ``` /** * @Description:自定义登录成功处理类,自定义登录失败处理类 **/ @Slf4j @Component public class SecurityAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler { @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException { UtilResponse.writeResult(response, null, "登录成功!"); } } ``` ``` /** * @Description:自定义登录失败处理类 **/ @Slf4j @Component public class SecurityAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler { @Override public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException { //用户名或密码错误 if (e instanceof BadCredentialsException || e instanceof UsernameNotFoundException) { UtilResponse.writeFailureResult(response, SystemStatusEnum.USERNAME_PASSWORD_ERROR.code, "用户名或密码错误"); } else if (e instanceof LockedException) { //账号被锁定 UtilResponse.writeFailureResult(response, SystemStatusEnum.ACCOUNT_LOCKED.code, SystemStatusEnum.ACCOUNT_LOCKED.desc); } else if (e instanceof DisabledException) { //账户被禁用 UtilResponse.writeFailureResult(response, SystemStatusEnum.ACCOUNT_DISABLE.code, SystemStatusEnum.ACCOUNT_DISABLE.desc); } else if (e instanceof AccountExpiredException) { //账户已过期 UtilResponse.writeFailureResult(response, SystemStatusEnum.ACCOUNT_EXPIRED.code, SystemStatusEnum.ACCOUNT_EXPIRED.desc); } else if (e instanceof CredentialsExpiredException) { //密码已过期 UtilResponse.writeFailureResult(response, SystemStatusEnum.PASSWORD_EXPIRED.code, SystemStatusEnum.PASSWORD_EXPIRED.desc); } else { UtilResponse.writeFailureResult(response, StatusCode.INTERNAL_SYSTEM_ERROR, "系统异常,登录失败!"); } } } ``` 4.在WebSecurityConfig进行引入 ![输入图片说明](https://images.gitee.com/uploads/images/2020/0807/173901_a8e8af48_5496301.png "屏幕截图.png") ``` @Resource private SecurityAuthenticationSuccessHandler successHandler; @Resource private SecurityAuthenticationFailureHandler failureHandler; @Resource private MyUsernameDetailsService myUsernameDetailsService; @Bean public CustomLoginAuthenticationFilter getCustomLoginAuthenticationFilter() { CustomLoginAuthenticationFilter filter = new CustomLoginAuthenticationFilter(); try { filter.setAuthenticationManager(this.authenticationManagerBean()); } catch (Exception e) { e.printStackTrace(); } // 设置登陆成功处理 filter.setAuthenticationSuccessHandler(successHandler); // 设置权限验证失败处理 filter.setAuthenticationFailureHandler(failureHandler); return filter; } ```