Spring Security(3)
您好,我是湘王,这是我的博客园,欢迎您来,欢迎您再来~
前面运行写好的代码之所以没有任何显示,是因为还没有对Spring Security进行配置,当然啥也不显示了。这就好比你坐在车上,却不打开发动机,车子当然跑不起来。所以咱们就来让它跑起来。不过在配置之前,有必要对Spring Security的登录流程做个大致了解。
如果深入源码去了解,这个玩意及其复杂,但是没必要,知道它的机制就行了。就好比你买车也不必把发动机拆开去看它是怎么工作的吧。简单来说它就是下面这些步骤:
1、Spring Security通过AuthenticationManager接口进行身份验证
2、ProviderManager是AuthenticationManager的一个默认实现
3、ProviderManager把验证工作委托给了AuthenticationProvider接口
4、AuthenticationProvider的实现类DaoAuthenticationProvider会检查身份认证
5、DaoAuthenticationProvider又把认证工作委托给了UserDetailsService接口
6、自定义UserDetailsService类从数据库中获取用户账号、密码、角色等信息,然后封装成UserDetails返回
7、使用Spring Security还需要自定义AuthenticationProvider接口,获取用户输入的账号、密码等信息,并封装成Authentication接口
8、将UserDetails和Authentication进行比对,如果一致就返回UsernamePasswordAuthenticationToken,否则抛出异常
下面是认证流程图:
首先重写loadUserByUsername:
/**
* 自定义用户详情
*
* @author 湘王
*/
@Service("userDetailsService")
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserService userService;
@Autowired
private RoleService roleService;
@Autowired
private UserRoleService userRoleService; @Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Collection<GrantedAuthority> authorities = new ArrayList<>();
// 从数据库中取出用户信息
SysUser user = userService.getByName(username);
// 判断用户是否存在
if(null == user) {
System.out.println("user is not exist");
throw new UsernameNotFoundException("user is not exist");
} // 获得用户角色:方式一
List<SysUserRole> list = userRoleService.getByUserId(user.getId());
// // 获得用户角色:方式二
// List<SysRole> list = roleService.getByUserId(user.getId()); // // 给用户添加授权:方式一
// for (SysUserRole userRole : list) {
// SysRole role = roleService.getById(userRole.getRoleid());
// authorities.add(new SimpleGrantedAuthority(role.getName()));
// }
// // 返回UserDetails实现类
// return new User(user.getName(), user.getPassword(), authorities); // 给用户添加授权:方式二
return User
.withUsername(username)
.password(user.getPassword())
.authorities(list.stream()
.filter(Objects::nonNull)// 判断是否为空
.map(userRole -> roleService.getById(userRole.getRoleid()))// 从SysUserRole获取Role
.map(SysRole::getName)// 转变为角色名称字符串
.map(SimpleGrantedAuthority::new)// 依据角色名称创建SimpleGrantedAuthority
.toArray(SimpleGrantedAuthority[]::new)// list转变为数组
).build();
}
}
因为UserDetailsService返回了封装的UserDetails,所以需要再自定义AuthenticationProvider返回Authentication接口:
/**
* 自定义登录验证
*
* @author 湘王
*/
@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
@Autowired
private CustomUserDetailsService customUserDetailsService; @Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// 获取表单输入中返回的用户名
String username = (String) authentication.getPrincipal();
// 获取表单中输入的密码
String password = (String) authentication.getCredentials();
// 这里调用我们的自己写的获取用户的方法
UserDetails userInfo = customUserDetailsService.loadUserByUsername(username);
if (userInfo == null) {
System.out.println("user is not exist");
throw new UsernameNotFoundException("user is not exist");
} PasswordEncoder passwordEncoder = new PasswordEncoder() {
@Override
public String encode(CharSequence charSequence) {
return charSequence.toString();
}
@Override
public boolean matches(CharSequence charSequence, String s) {
return s.equals(charSequence.toString());
}
}; // 采用简单密码验证
if (!passwordEncoder.matches(password, userInfo.getPassword())) {
System.out.println("user or password error");
throw new BadCredentialsException("user or password error");
} Collection<? extends GrantedAuthority> authorities = userInfo.getAuthorities();
// 构建返回的用户登录成功的token
return new UsernamePasswordAuthenticationToken(userInfo, password, authorities);
} @Override
public boolean supports(Class<?> aClass) {
return true;
}
}
接着来实现实现WebSecurityConfigurerAdapter,它通过重写WebSecurityConfigurerAdapter中的相关方法(一般是configurer)来自定义配置。WebSecurityConfigurerAdapter主要做几件事:
1、初始化
2、开启Security
3、配置各种过滤器,实现验证过滤器链
下面是它的代码:
/**
* spring security验证配置
*
* @author 湘王
*/
// 配置类
@Configuration
// 开启Security服务
@EnableWebSecurity
// 开启全局Securtiy注解
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private CustomUserDetailsService customUserDetailsService;
@Autowired
private CustomAuthenticationProvider authenticationProvider; // 自定义的登录验证逻辑
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider);
}
// 控制逻辑
@Override
protected void configure(HttpSecurity http) throws Exception {
// 执行UsernamePasswordAuthenticationFilter之前添加拦截过滤
http.addFilterBefore(new CustomInterceptorFilter(), UsernamePasswordAuthenticationFilter.class); http.authorizeRequests()
.anyRequest().authenticated()
// 设置自定义认证成功、失败及登出处理器
.and().formLogin().loginPage("/login")
.and().cors()
.and().csrf().disable();
}
@Override
public void configure(WebSecurity web) throws Exception {
// 设置拦截忽略文件夹,可以对静态资源放行
web.ignoring().antMatchers("/css/**", "/js/**");
}
}
接着用postman进行测试:
回顾整个调用过程,它的时序图是:
但是等等:好像除了/login,其他方法都不能正常访问!
感谢您的大驾光临!咨询技术、产品、运营和管理相关问题,请关注后留言。欢迎骚扰,不胜荣幸~
Spring Security(3)的更多相关文章
- Spring Security(08)——intercept-url配置
http://elim.iteye.com/blog/2161056 Spring Security(08)--intercept-url配置 博客分类: spring Security Spring ...
- Spring Security(三)
Spring Security(三) 个性化用户认证流程 自定义登录页面 在配置类中指定登录页面和接收登录的 url @Configuration public class BrowserSecuri ...
- Spring Security(二)
Spring Security(二) 注:凡是源码部分,我已经把英文注释去掉了,有兴趣的同学可以在自己项目里进去看看.:-) 定义用户认证逻辑 用户登录成功后,用户的信息会被 Security 封装在 ...
- Spring Security(一)
Spring Security(一) 基本原理 前言 Spring Security核心功能 认证(你是谁) 授权(你能干什么) 攻击防护(防止伪造身份) Srping Security基本原理 项目 ...
- 【权限管理系统】Spring security(三)---认证过程(原理解析,demo)
在前面两节Spring security (一)架构框架-Component.Service.Filter分析和Spring Security(二)--WebSecurityConfigurer配 ...
- SpringBoot集成Spring Security(7)——认证流程
文章目录 一.认证流程 二.多个请求共享认证信息 三.获取用户认证信息 在前面的六章中,介绍了 Spring Security 的基础使用,在继续深入向下的学习前,有必要理解清楚 Spring Sec ...
- SpringBoot集成Spring Security(6)——登录管理
文章目录 一.自定义认证成功.失败处理 1.1 CustomAuthenticationSuccessHandler 1.2 CustomAuthenticationFailureHandler 1. ...
- SpringBoot集成Spring Security(5)——权限控制
在第一篇中,我们说过,用户<–>角色<–>权限三层中,暂时不考虑权限,在这一篇,是时候把它完成了. 为了方便演示,这里的权限只是对角色赋予权限,也就是说同一个角色的用户,权限是 ...
- SpringBoot集成Spring Security(4)——自定义表单登录
通过前面三篇文章,你应该大致了解了 Spring Security 的流程.你应该发现了,真正的 login 请求是由 Spring Security 帮我们处理的,那么我们如何实现自定义表单登录呢, ...
- SpringBoot集成Spring Security(2)——自动登录
在上一章:SpringBoot集成Spring Security(1)——入门程序中,我们实现了入门程序,本篇为该程序加上自动登录的功能. 文章目录 一.修改login.html二.两种实现方式 2. ...
随机推荐
- git merge和git rebase总结
dev分支 * da349ef (dev) e * 75350bc d * 63cbbb8 c * c6509a5 b * 13405af a 文件可能会发生冲突,需要解决一下 aaaaaaaaa b ...
- python的环境,你再也不用愁-conda
Conda Guide Conda简介 conda是一个包,依赖和环境管理工具,适用于多种语言,如: Python, R, Scala, Java, Javascript, C/ C++, FORTR ...
- 华南理工大学 Python第6章课后测验-2
1.(单选)以下关于语句 a = [1,2,3,(4,5)]的说法中,正确的个数有( )个.(1)a是元组类型 (2)a是列表类型 (3)a有5个元素 (4)a有4个元素(5)a[1] ...
- 从 Hadoop 到云原生, 大数据平台如何做存算分离
Hadoop 的诞生改变了企业对数据的存储.处理和分析的过程,加速了大数据的发展,受到广泛的应用,给整个行业带来了变革意义的改变:随着云计算时代的到来, 存算分离的架构受到青睐,企业开开始对 Hado ...
- Traefik 2.0 实现灰度发布
文章转载自:https://mp.weixin.qq.com/s?__biz=MzU4MjQ0MTU4Ng==&mid=2247484478&idx=1&sn=238390dc ...
- 回滚Deployment控制器下的应⽤发布
若因各种原因导致滚动更新⽆法正常进⾏,如镜像⽂件获取失败."⾦丝雀"遇险等,则应该将应⽤回滚到之前的版本,或者回滚到由⽤户指定的历史记录中的版本. Deployment控制器的回滚 ...
- JuiceFS 在 Elasticsearch/ClickHouse 温冷数据存储中的实践
企业数据越存越多,存储容量与查询性能.以及存储成本之间的矛盾对于技术团队来说是个普遍难题.这个难题在 Elasticsearch 与 ClickHouse 这两个场景中尤为突出,为了应对不同热度数据对 ...
- C#并发编程-4 同步
如果程序用到了并发技术,那就要特别留意这种情况:一段代码需要修改数据,同时其他代码需要访问同一个数据. 这种情况就需要考虑同步地访问数据. 如果下面三个条件都满足,就必须用同步来保护共享的数据. 多段 ...
- aws-cli命令-ec2实例相关的操作
aws上可以使用aws-cli的方式管理实例,记录一些常用的操作 1.启动.关闭.终止实例(目前笔者发现只能通过指定实例ID进行管理) # 启动/关闭/重启 指定的实例 aws ec2 start-i ...
- CSP-J2020 洛谷P7072 直播获奖(Splay/桶排序)
题目描述 NOI2130 即将举行.为了增加观赏性,CCF 决定逐一评出每个选手的成绩,并直播即时的获奖分数线.本次竞赛的获奖率为 w%,即当前排名前 w% 的选手的最低成绩就是即时的分数线. 更具体 ...