创建个项目
引入Spring Web和Spring Security 即可
写个Controller接收请求 转发重定向都可以
static下定义两个页面
login.html页面 用来登录
main.html如果可以跳到这里,说明登录成功
启动运行程序
我们访问登录接口 或者是访问静态资源都会重定向到这个页面
这个页面说明 Spring Security已经生效
任何访问资源,都需要此操作登录再操作
用户名 user
密码是启动时在控制台输出的这串 且每次启动都是不一样的
也就是说引入Spring Security依赖后,对接口访问和静态页面的访问都进行了控制
首先,第一点,即使我不觉得你的登录页面丑,用户名,密码总要去数据库查询出来的,不可能,每次用user,然后去看控制台
那么需要实现两个接口
UserDetailsService 和 PasswordEncode 命名也好记
现在大概了解下UserDetailsService
返回的这个UserDetails
而返回的UserDetails也是个接口,正常肯定由个实现类
。。。。。
注意User这个类,可能和我们平时定义的User注意要区分,另外 User里面的password是数据库查出来的,而不是前端传进来的
大概原理是这样,前端传进来一个userName,然后我们去查数据库,没有,那么就没有,有的话,将密码,权限,什么乱七八糟的交给它
我们需要自定用户名密码这些的话,除了要实现UserDetailsService还要实现PasswordEncode
大概了解下PasswordEncode
其实在我们引入Spring Security时候可以看出来 Spring Security自带默认肯定有这么个实例了
测试一下这个加密
那么Spring Security是如果判断加密后的密码和原来的密码是否相同呢
且加密后的密码是单向的,不知道的原始密码是无法破解,.......这个无法破解还是算了
那么这里就是大概原理了解了一点点 一丢丢
那么可以这么说:这个PasswordEncode就是对我从数据库通过用户名找到的密码进行加解密的
下面我们来实现自定义的登录逻辑:但是Spring Security有要求,就是你要实现自定义的登录逻辑,需要容器内先要有个PasswordEncode的实例
需要写个配置类
另外还要写个类实现UserDetailsService接口
现在启动程序 控制台不再打印密码
输入admin 123456就可以访问了
自定义登录逻辑就写完了
那么如何自定义登录页面呢
实现自定义登录页面很简单
让原先定义的配置类 继承 WebSecurityConfigurerAdpter
这样一来,Spring Security就将页面访问控制权交给了我们自己 它的页面就失效
但是随之带来的问题是,我们现在既可以访问login.html main.html 好像访问控制权限已经完全失效了
那么就需要授权方面的一些什么什么什么的
重新启动程序,发现所有页面又都没不能访问了
上面的写法意思就是所有请求,都必须认证, 也就是说,这样写,把门都堵死了,那么开个门
启动程序
但是又出现个问题,就是登录没有反应
发现Spring Security并没有拦截我们的登录请求,就是根本没进这个方法来
还是没反应 关闭csrf防护 不知道
现在登录终于访问方法了
但是放心debug后 页面报错
原因时,登录成功后没有指定跳转到哪个页面
控制器根本没进来,也就是一切还是Spring Security控制着
需要告诉Spring Security登录成功后跳转到哪个页面
启动
原因在于Spring Security要求 登录成功后的跳转页面必须是Post请求
也就是说原先的登录就是摆设
,当用户名,密码输入错误的时候, 比如说,当某些时候,业务需要让它去error页面的情况如何操作呢
先自定一个error页面
如果登录失败
关于设置请求账户和密码的参数名
那么Spring Security具体是怎么做到的
查看UsernamePasswordAuthenticationFilter
原来你是这么干的
如何改掉固定参数名
这样的话就改掉了,那么我们自定义的登录页面也需要修改下
下面看一个问题,它其实是转发到我们的控制去
但是直接让它在这里进行外部资源访问,它是做不到的
当然我们可以转发到控制器再进行重定向
但是直接让它
重写AuthenticationSuccessHandler
换一种写法,显得很low
注释掉
现在很多项目都是前后端分离
大概理解.......
输入admin 123456
这种时候就比百度难多了
需要干点事
注意:password为null??????? 这是Spring Security考虑到安全原因输出为null
上面这些信息不就是这里放进去的吗
自定义登录成功处理器就这么回事,也是不能和failureForwardUrl共存的
下面自定义登录失败处理器,那不就是照葫芦画瓢么
运行自己可以试下
授权认证,其实和MVC拦截器比较类似,拦截或者放行
上面anyRequest就是所有请求都需要做什么事 一般都是.anyRequest().authenticated().即都需要被认证,即登录后可以访问
而anyMatchers就是匹配某些,实际工作中可以这么配置如下
比如说一般
static下有js,css,images等
配置下
这样就可以访问到了,即使你没有登录
关于regexMathcers
很明显,是一个正则的匹配方式
另外无论是antMathcers还是regexMathcers不单只有上面演示的一个参数的方法
还有一个两个参数的方法
HttpMethod就是Http的请求方式,
这里就用regexMathcers演示,antMathcers也一样的
说明不光可以对静态文件放行,还可以对接口放行
另外一个就是如果传入POST,或者GET等等,就要注意,接口上的请求方式了,必须吻合
例如 这种时候要么@GetMapping要么@RequestMapping
如果用@Post或者其他
这样就会出问题
关于mvcMathcers
它主要配置了一个servletPath的情况
这个servletPath,指的就是
在没有使用Spring Security之前,这样配置就是说所有的访问
localhost:8080/xxxx这么个意思
但是如果使用了Spring Security,再这样配置是不行的
比如我现在配置了这个
访问 localhost:8080/xxxx/demo 直接跳到了
原因
也就是说用了Spring Security之后这个配置难道就不能配了?该如何解决
试下
现在我们大概了解
关于Spring Security的访问控制方法
我们点击
可以看到有6个访问控制
内置访问控制介绍:
1.permitAll:允许任何人都可以来访问
2.denyAll:所有人都不能访问
3.anonymous:匿名访问,和permitAll相似,只不过anonymous会到一个拦截连
4.authenticated:都需要相应认证
5.fullyAuthenticated:完全认证
6.rememberMe:记住我功能
常用的就是permitAll和authenticated,我们已经用过了,还有一个rememberMe
关于权限判断
这里讲的是登录之后
hasAuthority()有某个权限可以访问
hasAnyAuthority()就是用户具备给定权限中的某一个就可以访问
注意权限 比如 "asd" "aAd" 是严格区分大小写的
而上面判断的权限就是自定义登录逻辑时候指定的
演示一下
admin 123456
说明都是OK的,那么我们现在将权限改掉
重启
403 Forbidden一般就是权限不足的错误
那么如果是这样的话
就可以了
上面是用户具有某些权限的判断,下面演示关于用户具有某些角色的判断
这个角色的判断,其实和权限的判断一样,在一开始登录时候自定义登录逻辑时候就可以放进去
只是当时没有写,下面就先在自定义登录逻辑里把角色加进去演示
角色的写法 ROLE_是固定写法,告诉SpringSecurity这是角色信息 abc就是角色 当然可以写多个
如果你写ROLE_abc,程序启动就会报错 且严格区分大小写
启动自己测试下
符合其中一个就行
那么下面这种情况呢
上面是权限 和 角色 对登录用户的访问控制
还有
是根据 IP地址 来对访问进行控制
比如说现在有个后端管理,只允许某个IP地址的用户进行操作,或者只允许自己服务器IP登录满足于这样需求的
这里注意下,因为是本机测试,输入localhost和输入127.0.0.1 或者是本机IP地址是不一样的,演示下
查看控制台
我们用127.0.0.1试下
本机ip地址
那么演示IP地址判断的话,就需要用本机IP地址了
这里指定127.0.0.1 能不能用192.168.10.71访问 main1.html呢
先用127.0.0.1测试
127.0.0.1可以访问
那么用另外个IP
权限判断 角色判断 IP地址判断 如果没有指定权限或者指定角色或者指定IP
那么都会跳转到403页面,但是浏览器的哪个页面也太丑了,体验好点就需要自定义了
下面是自定义403处理方案
实现AccessDeniedHandler
自己想像
演示,因为现在只允许127.0.0.1去main1.html
下面介绍access方法使用
我们可以点进去看它里面 权限 角色 IP 全都是用的access方法
和原先效果是一样的
这个叫access表达式
access就是权限 角色 IP 判断的底层实现
在项目中很有可能出现需要自定义方法实现权限控制的情况
比如说,我们的项目现在需求是这样的,有没有访问当前URL的权限,有就可以访问,没有就不让访问
那么我们就来自定义access
自定义 方法名随意
测试
原因是我们没把这个权限在自定义登录逻辑里加进去
重启 测试
可以到main1原因
@某个bean名是固定写法
以上都是通过配置类去实现访问控制
其实Spring Security提供了通过注解的方式控制访问
通过在启动类或者配置类添加@EnableGlobalMethodSecurity 开启Spring Security注解方式控制
如果设置的条件允许,程序正常执行,如果权限不允许报500,就是说先会请求到登录页,登录后如果没有权限报500
org.springframework.security.access.AccessDeniedException:不允许访问
这些注解可以写到Service接口或方法上,也可以写道Controller或者Controller的方法上,通常情况下都是卸载控制器方法上的,控制接口URL是否允许被访问
@Secured是专门用来判断是否具有角色的.能写在方法或类上.参数要以ROLE_开头
演示 先修改下配置类 就是所有都需要验证,只留登录页 error页面
启动类上加上该注解
自定义登录逻辑里是有这个角色的,大小写严格区分 ROLE_
那么这样就是可以访问的
测试
修改下
这个@Secured("ROLE_abc")也可以不用里面非加括号 且严格区分大小写,必须写ROLE_
看控制台
注意
下面是后来复习时重敲了一遍 一直报自定义的那个异常
下图是后来复习时候在application.properties里加了
再介绍两个注解 @PreAuthorze 和 @PostAuthorize
@PreAuthorze:表示访问方法或类在执行之前先判断权限,大多情况下都是使用这个注解,注解的参数和access()方法参数取值相同,都是权限表达式access("hasAuthority('ROLE_abc')")
@PostAuthorize:表示方法或类执行结束后判断权限,此注解很少被使用到
现在演示使用
首先
还可以写@PreAuthorize("hasRole('ROLE_abc')")
还可以写@PreAuthorize("hasAnyAuthority('admin')")
关于RememberMe功能
Spring Security中Remember Me为"记住我"功能,用户只需要在登录时添加 remember-me复选框,取值为true,Spring Security会自动把用户信息存储到数据源,以后就可以不登陆进行访问.
Spring Security实现Remeber Me功能时,底层实现以来Spring-JDBC,所以需要导入Spring-JDBC.
但现在大部分使用的是Mybatis框架,很少直接使用Spring-JDBC,所以可以直接导入mybatis启动器加Mysql驱动
导入之后在 application.properties里配置好数据源,根据自己实际情况配置
那么数据库连接就没有问题了
下面配置Remeber Me功能
登录页面
测试 启动后看下数据库
自动建了张表
username用户名
series主键
token令牌
last_used最后登录时间
现在去登录
登录成功的话,第一次该表会自动创建 series是主键 记得第二次启动把建表注释掉 不然会报错表已经存在
这个记住我功能,没仔细研究,Cookie会有一个remember-me,定时清楚,关闭浏览器后定时消失
将网页关掉,再次访问localhost:8080/main.html 就不需要再次登录
这里默认记住我功能的时间是2周,可以配置时间
测试OK
注意
Thymeleaf中Spring Security的使用
Spring Security可以在一些视图技术中进行控制显示效果.例如JSP或Thymeleaf.在非前后端分离且使用SpringBoot的项目中使用Thymeleaf做为视图展现技术。
Thmeleaf对Spring Security的支持都放在thymeleaf-extras-springsecurity中
所以需要在项目中添加依赖,和Thmeleaf依赖
在html页面中引入Thmeleaf和security的命名空间
在Controller里做个页面跳转 加个内部转发
测试
登录后访问demo接口 由于是复习时写的 这里
上面就是在Thmeleaf中获取登录用户属性相关操作
demo.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
登录账号:<span sec:authentication="name"></span><br/>
登录用户名:<span sec:authentication="principal.username"></span><br/>
凭证:<span sec:authentication="credentials"></span><br/>
权限和角色:<span sec:authentication="authorities"></span><br/>
客户端地址:<span sec:authentication="details.remoteAddress"></span><br/>
sessionId:<span sec:authentication="details.sessionId"></span><br/>
</body>
</html>
下面说下Thmeleaf中进行权限判断
比如有增删改查的按钮,哪些用户根据权限判断,显示各自权限可以看到的按钮
也可以根据角色判断
哪些按钮可以点,哪些按钮不能点,哪些按钮对谁显示,不对谁显示
比如在自定义逻辑类里
demo.html
测试
退出功能很简单,演示 价格/logout的超链接即可
测试
点击退出
如果说加了上下文,也只要写/logout
地址栏会有个?logout 其实这就已经退出了,再访问其他页面都会跳转到登录页面
如果不想要后面跟着的?logout,也可以配置
可以自己测试
如果html那边不想写/logout
测试
点击退出 一样可以到登录页 其实也没必要的
下面了解下CSRF
讲人话:就是跨域情况下,sessionId有可能被第三方劫持,比如你管理员登录账号,跨域情况下如果被第三方劫持,知道了你的sessionId,第三方很可能冒充管理员.
Spring Security4开始,不管你是不是跨域请求,都会做CSRF防护.默认开启
要求访问着携带参数名为_csrf值为token,和服务端进行匹配.至于第三方如何劫持.不懂
启动测试
如果你不携带
是登录不了的,这里只做大概了解
学习时候csrf关闭,但是正式环境还是要打开的