# 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

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 extends GrantedAuthority> 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的实现对象,这里采用的如下

通过继承抽象类来继承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参数。

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进行引入

```
@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;
}
```