在阅读本文之前可以先看看springsecurity的基本执行流程,下面我展示一些核心配置文件,后面给出完整的整合代码到git上面,有兴趣的小伙伴可以下载进行研究

  使用maven工程构建项目,首先需要引入最核心的依赖,

        <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

由于这里我们整合的项目进行了前后端分离,所以我们首先需要自定义登录成功和失败,登出成功的自定义处理类

其实就是实现不同的handler即可:1.首先我们来看登录成功的处理类

/**
* 处理登录验证成功的类
* @author zhoukebo
* @date 2018/9/4
*/
@Component
public class FuryAuthSuccessHandler implements AuthenticationSuccessHandler {
/**Json转化工具*/
@Autowired
private ObjectMapper objectMapper; @Override
public void onAuthenticationSuccess(HttpServletRequest request,HttpServletResponse response, Authentication authentication) throws IOException{
SysUser userDetails = (SysUser)authentication.getPrincipal();
System.out.println("管理员 " + userDetails.getUsername() + " 登录");
Map<String,String> map=new HashMap<>(2);
map.put("code", "200");
map.put("msg", "登录成功");
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(objectMapper.writeValueAsString(map));
} }

2.登录验证失败的类

/**
* 处理登录验证失败的类
* @author zhoukebo
* @date 2018/9/4
*/
@Component
public class FuryAuthFailureHandler implements AuthenticationFailureHandler { @Autowired
private ObjectMapper objectMapper; @Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
System.out.println("登录验证失败");
Map<String,String> map=new HashMap<>(2);
map.put("code", "10001");
map.put("msg", exception.getMessage());
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(objectMapper.writeValueAsString(map));
}
}

3.自定义处理注销成功的类

/**
* 处理注销成功
* @author zhoukebo
* @date 2018/9/4
*/
@Component
public class MyLogoutSuccessHandler implements LogoutSuccessHandler { /**Json转化工具*/
@Autowired
private ObjectMapper objectMapper; @Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException{
Map<String,String> map=new HashMap<>(2);
map.put("code", "200");
map.put("msg", "登出成功");
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(objectMapper.writeValueAsString(map));
}
}

4.自定义没有权限的处理类

/**
* 处理没有权限的类
* @author zhoukebo
* @date 2018/9/5
*/
@Component
public class RestAuthAccessDeniedHandler implements AccessDeniedHandler { @Autowired
private ObjectMapper objectMapper; @Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e) throws IOException, ServletException {
Map<String,String> map=new HashMap<>(2);
map.put("code", "403");
map.put("msg", e.getMessage());
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(objectMapper.writeValueAsString(map));
}
}

然后对springsecurity进行详细的配置需要继承WebSecurityConfigurerAdapter类,下面是配置文件的详情

/**
* spring Security配置安全控制中心
*
* @author zhoukb
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
/**
* 依赖注入自定义的登录成功处理器
*/
@Autowired
private FuryAuthSuccessHandler furyAuthSuccessHandler;
/**
* 依赖注入自定义的登录失败处理器
*/
@Autowired
private FuryAuthFailureHandler furyAuthFailureHandler;
/**
* 依赖注入自定义的注销成功的处理器
*/
@Autowired
private MyLogoutSuccessHandler myLogoutSuccessHandler; /**
* 注册没有权限的处理器
*/
@Autowired
private RestAuthAccessDeniedHandler restAuthAccessDeniedHandler; /***注入自定义的CustomPermissionEvaluator*/
@Bean
public DefaultWebSecurityExpressionHandler webSecurityExpressionHandler() {
DefaultWebSecurityExpressionHandler handler = new DefaultWebSecurityExpressionHandler();
handler.setPermissionEvaluator(new CustomPermissionEvaluator());
return handler;
} /***注入我们自己的登录逻辑验证器AuthenticationProvider*/
@Autowired
private AuthenticationProvider authenticationProvider; @Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//这里可启用我们自己的登陆验证逻辑
auth.authenticationProvider(authenticationProvider);
} /**
* 配置spring security的控制逻辑
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
//"/login"不进行权限验证
.antMatchers("/login").permitAll()
.antMatchers("/favicon.ico").permitAll()
.anyRequest().authenticated() //其他的需要登陆后才能访问
.and()
.formLogin()
//loginProcessingUrl用于指定前后端分离的时候调用后台登录接口的名称
.loginProcessingUrl("/login")
//配置登录成功的自定义处理类
.successHandler(furyAuthSuccessHandler)
//配置登录失败的自定义处理类
.failureHandler(furyAuthFailureHandler)
.and()
//loginProcessingUrl用于指定前后端分离的时候调用后台注销接口的名称
.logout().logoutUrl("/logout")
.logoutSuccessHandler(myLogoutSuccessHandler)
.and()
//配置没有权限的自定义处理类
.exceptionHandling().accessDeniedHandler(restAuthAccessDeniedHandler)
.and()
.cors()//新加入
.and()
.csrf().disable();// 取消跨站请求伪造防护
}
}

上面我们配置了自定义的登录逻辑的验证MyAuthenticationProvider,和自定义的权限验证CustomPermissionEvaluator代码如下

/**
* 实现自己的AuthenticationProvider类,用来自定义用户校验机制
* @author zhoukebo
* @date 2018/9/5
*/
@Component
public class MyAuthenticationProvider implements AuthenticationProvider { @Autowired
private CustomerDetailService customerDetailService; @Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// 获取表单输入中返回的用户名;
String userName = (String) authentication.getPrincipal();
// 获取表单中输入的密码;
String password = (String) authentication.getCredentials();
// 这里调用我们的自己写的获取用户的方法;
UserDetails userInfo = customerDetailService.loadUserByUsername(userName);
if (userInfo == null) {
throw new BadCredentialsException("用户名不存在");
} // 这里我们还要判断密码是否正确,这里我们的密码使用BCryptPasswordEncoder进行加密的
if (!new BCryptPasswordEncoder().matches(password, userInfo.getPassword())) {
throw new BadCredentialsException("密码不正确");
}
// 这里还可以加一些其他信息的判断,比如用户账号已停用等判断。 Collection<? extends GrantedAuthority> authorities = userInfo.getAuthorities();
// 构建返回的用户登录成功的token
return new UsernamePasswordAuthenticationToken(userInfo, password, authorities);
} @Override
public boolean supports(Class<?> authentication) {
// 这里直接改成retrun true;表示是支持这个执行
return true;
}
}
/**
* 我们需要自定义对hasPermission()方法的处理,
* 就需要自定义PermissionEvaluator,创建类CustomPermissionEvaluator,实现PermissionEvaluator接口。
* @author zhoukebo
* @date 2018/9/5
*/
@Component
public class CustomPermissionEvaluator implements PermissionEvaluator {
/**
* 自定义验证方法
* @param authentication 登录的时候存储的用户信息
* @param targetDomainObject @PreAuthorize("hasPermission('/hello/**','r')") 中hasPermission的第一个参数
* @param permission @PreAuthorize("hasPermission('/hello/**','r')") 中hasPermission的第二个参数
* @return
*/
@Override
public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
// 获得loadUserByUsername()方法的结果
SysUser user = (SysUser)authentication.getPrincipal();
// 获得loadUserByUsername()中注入的权限
Collection<? extends GrantedAuthority> authorities = user.getAuthorities();
// 遍历用户权限进行判定
for(GrantedAuthority authority : authorities) {
UrlGrantedAuthority urlGrantedAuthority = (UrlGrantedAuthority) authority;
String permissionUrl = urlGrantedAuthority.getPermissionUrl();
// 如果访问的Url和权限用户符合的话,返回true
if(targetDomainObject.equals(permissionUrl)) {
return true;
}
}
return false;
} @Override
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
return false;
}
}

注意:上面的自定义权限要生效还需要在WebSecurityConfig上面加上注解@EnableGlobalMethodSecurity(prePostEnabled = true)

完成登录逻辑还需要我们实现UserDetailsService接口,以便系统能够根据用户名去获取用户的信息,里面还可加上自己的逻辑

/**
* 需要自定义UserDetailsService实现spring security的UserDetailsService接口
* @author zhoukebo
* @date 2018/9/4
*/
@Service
public class CustomerDetailService implements UserDetailsService { @Autowired
SysUserRepository userRepository; @Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
SysUser user = userRepository.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("用户名不存在");
}
List<SysRole> roles = user.getRoles(); //将所有的角色对应的资源权限全部放入user对应的grantedAuthority集合中
for (SysRole role : roles) {
List<SysResource> resources = role.getResources();
List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
for (SysResource resource : resources) {
if (resource != null && resource.getResourceName()!=null) {
GrantedAuthority grantedAuthority = new UrlGrantedAuthority(resource.getMethodPath(),resource.getResourceName());
grantedAuthorities.add(grantedAuthority);
}
}
user.setGrantedAuthority(grantedAuthorities);
} System.out.println("s:" + username);
return user;
}
}

以上就完成了springboot和springsecurity的整合工作,demo中包含两种自定义权限验证,有兴趣的小伙伴可以自行在github上面下载下来研究,不懂得可以交流,代码有什么不妥的地方也望大家互相指教

github示例代码

springboot2.0整合springsecurity前后端分离进行自定义权限控制的更多相关文章

  1. SpringBoot2.0.3 + SpringSecurity5.0.6 + vue 前后端分离认证授权

    新项目引入安全控制 项目中新近添加了Spring Security安全组件,前期没怎么用过,加之新版本少有参考,踩坑四天,终完成初步解决方案.其实很简单,Spring Security5相比之前版本少 ...

  2. SpringBoot2.0整合SpringSecurity实现WEB JWT认证

    相信很多做技术的朋友都做过前后端分离项目,项目分离后认证就靠JWT,费话不多说,直接上干活(写的不好还请多多见谅,大牛请绕行) 直接上代码,项目为Maven项目,结构如图: 包分类如下: com.ap ...

  3. Spring Boot Security JWT 整合实现前后端分离认证示例

    前面两章节我们介绍了 Spring Boot Security 快速入门 和 Spring Boot JWT 快速入门,本章节使用 JWT 和 Spring Boot Security 构件一个前后端 ...

  4. Vue+Django2.0 restframework打造前后端分离的生鲜电商项目(2)

    1.restful api介绍 1.前后端分离的优缺点 1.为什么要用前后端分离 1.pc.app.pad多端适应 2.SPA(单页面应用)开发模式开始流行 3.前后端分离职责不清 4.开发效率问题, ...

  5. Spring Boot + Vue 前后端分离开发,权限管理的一点思路

    在传统的前后端不分的开发中,权限管理主要通过过滤器或者拦截器来进行(权限管理框架本身也是通过过滤器来实现功能),如果用户不具备某一个角色或者某一个权限,则无法访问某一个页面. 但是在前后端分离中,页面 ...

  6. SpringBoot+Shiro+JWT前后端分离实现用户权限和接口权限控制

    1. 引入需要的依赖 我使用的是原生jwt的依赖包,在maven仓库中有好多衍生的jwt依赖包,可自己在maven仓库中选择,实现大同小异. <dependency> <groupI ...

  7. SpringBoot2.0 整合 SpringSecurity 框架,实现用户权限安全管理

    本文源码:GitHub·点这里 || GitEE·点这里 一.Security简介 1.基础概念 Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方 ...

  8. springboot整合ueditor 前后端分离

    1.下载ueditor,百度搜索ueditor,下载 前端用的是Jsp版,导入文件如下 由于要修改部分源码,所以后端用的源码版,导入文件如下 2.配置路径,用来找到json文件 配置前端ueditor ...

  9. Vue+Django2.0 restframework打造前后端分离的生鲜电商项目(3)

    1.drf前期准备 1.django-rest-framework官方文档 https://www.django-rest-framework.org/ #直接百度找到的djangorestframe ...

随机推荐

  1. awesome mac

    https://proxyman.app/ https://proxie.app/docs/#how-does-it-work https://github.com/kyleduo/TinyPNG4M ...

  2. Java类初始化顺序,大神3个示例带你躺坑。。

    最近发现微信群里面有些群友在讨论类的初始化顺序,如类的静态变量.成员变量.静态代码块.非静态代码块.构造器,及继承父类时,它们的初始化顺序都是怎样的,下面我通过例子来说明这个情况,以免被人误导. 示例 ...

  3. python接口自动化(put请求)

    python接口自动化(put请求) 一.put请求的作用:更新资源 二.应用 导包:import requests 调用requests.put()方法 参数有URL.data.headers,方法 ...

  4. 【HDOJ】P5056 Boring count

    题目意思是给你一个字符串和K,让你求其中有多少个字串中每个字母的出现次数不超过K次,可以等于 题目意思是很简单的,写起来也很简单,不过就是注意最后要是long long要不WA了,555~ #incl ...

  5. 【centos】 error: command 'gcc' failed with exit status 1 错误

    转载自 :http://blog.csdn.net/fenglifeng1987/article/details/38057193 用安装Python模块出现error: command 'gcc' ...

  6. Linux 系统 /var/log/journal/ 垃圾日志清理

    CentOS系统中有两个日志服务,分别是传统的 rsyslog 和 systemd-journal systemd-journald是一个改进型日志管理服务,可以收集来自内核.系统早期启动阶段的日志. ...

  7. 伪类元素before&after

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  8. leetcode-第11场双周赛-5089-安排会议日程

    题目描述: 自己的提交: class Solution: def minAvailableDuration(self, slots1: List[List[int]], slots2: List[Li ...

  9. The chance for love doesn't come around every day.

    The chance for love doesn't come around every day.爱的机会不是每天都有的.

  10. Python:Logging日志处理

    程序中,需要添加日志来记录大量信息. import logging # 第一步:创建logger self.logger = logging.getLogger() self.logger.setLe ...