第一节 Spring Security 简介
Spring 是一个非常流行和成功的 Java 应用开发框架。Spring Security 基于 Spring 框架,提供了一套 Web 应用安全性的完整解决方案。一般来说,Web 应用的安全性包括用户认证(Authentication)和用户授权(Authorization)两个部分。
-
用户认证指的是验证某个用户是否为系统中的合法主体,也就是说用户能否访问该系统。用户认证一般要求用户提供用户名和密码。系统通过校验用户名和密码来完成认证过程。
-
用户授权指的是验证某个用户是否有权限执行某个操作。在一个系统中,不同用户所具有的权限是不同的。比如对一个文件来说,有的用户只能进行读取,而有的用户可以进行修改。一般来说,系统会为不同的用户分配不同的角色,而每个角色则对应一系列的权限。
对于上面提到的两种应用情景,Spring Security 框架都有很好的支持。在用户认证方面,Spring Security 框架支持主流的认证方式,包括 HTTP 基本认证、HTTP 表单验证、HTTP 摘要认证、OpenID 和 LDAP 等。在用户授权方面,Spring Security 提供了基于角色的访问控制和访问控制列表(Access Control List,ACL),可以对应用中的领域对象进行细粒度的控制。
第二节 Spring Security 核心组件
1. Authentication 认证
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#aa5500">//这个接口的实现类都是Token,称为票据,UsernamePasswordAuthenticationToken</span>
<span style="color:#aa5500">//我们自定义实现就可以叫MobileCodeAuthenticationToken</span>
<span style="color:#770088">public</span> <span style="color:#770088">interface</span> <span style="color:#0000ff">Authentication</span> <span style="color:#770088">extends</span> <span style="color:#000000">Principal</span>, <span style="color:#000000">Serializable</span> {
<span style="color:#aa5500">/**</span>
<span style="color:#aa5500">* 权限列表</span>
<span style="color:#aa5500">*/</span>
<span style="color:#000000">Collection</span><span style="color:#981a1a"><?</span> <span style="color:#770088">extends</span> <span style="color:#000000">GrantedAuthority</span><span style="color:#981a1a">></span> <span style="color:#000000">getAuthorities</span>();
<span style="color:#aa5500">/**</span>
<span style="color:#aa5500">* 认证凭据,可能是密码,也可能是验证码,也可能是其他认证凭据</span>
<span style="color:#aa5500">*/</span>
<span style="color:#008855">Object</span> <span style="color:#000000">getCredentials</span>();
<span style="color:#aa5500">/**</span>
<span style="color:#aa5500">* 认证请求的详细信息,可能是IP地址,也可能是认证序列号,也可能是null</span>
<span style="color:#aa5500">*/</span>
<span style="color:#008855">Object</span> <span style="color:#000000">getDetails</span>();
<span style="color:#aa5500">/**</span>
<span style="color:#aa5500">* 如果通过认证,则返回的是包含(用户名和密码)或者(手机号和验证码)等的对象;如果认证不通过,</span>
<span style="color:#aa5500">* 则返回的是用户名或者手机号等。</span>
<span style="color:#aa5500">*/</span>
<span style="color:#008855">Object</span> <span style="color:#000000">getPrincipal</span>();
<span style="color:#aa5500">/**</span>
<span style="color:#aa5500">* 是否认证通过</span>
<span style="color:#aa5500">*/</span>
<span style="color:#008855">boolean</span> <span style="color:#000000">isAuthenticated</span>();
<span style="color:#aa5500">/**</span>
<span style="color:#aa5500">* 修改认证状态</span>
<span style="color:#aa5500">*/</span>
<span style="color:#008855">void</span> <span style="color:#000000">setAuthenticated</span>(<span style="color:#008855">boolean</span> <span style="color:#000000">isAuthenticated</span>) <span style="color:#770088">throws</span> <span style="color:#000000">IllegalArgumentException</span>;
}</span></span>
Authentication接口就是用来携带认证信息的。认证信息包括用户身份信息,密码,及权限列表等
2. UsernamePasswordAuthenticationFilter
账号密码认证过滤器,用于认证用户信息,认证方式是由 AuthenticationManager 接口提供。
3. AuthenticationManager
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">public</span> <span style="color:#770088">interface</span> <span style="color:#0000ff">AuthenticationManager</span> {
<span style="color:#aa5500">/**</span>
<span style="color:#aa5500">* 尝试认证传递过来的认证信息,如果认证成功,则会修改认证信息的状态。否则,则会抛出异常</span>
<span style="color:#aa5500">*/</span>
<span style="color:#000000">Authentication</span> <span style="color:#000000">authenticate</span>(<span style="color:#000000">Authentication</span> <span style="color:#000000">authentication</span>) <span style="color:#770088">throws</span> <span style="color:#000000">AuthenticationException</span>;
}</span></span>
认证管理器,是认证相关的核心接口,也是发起认证的出发点。实际业务中可能根据不同的信息进行认证,所以Spring推荐通过实现 AuthenticationManager 接口来自定义自己的认证方式。Spring 提供了一个默认的实现 ProviderManager。
4. ProviderManager
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">ProviderManager</span> <span style="color:#770088">implements</span> <span style="color:#000000">AuthenticationManager</span>, <span style="color:#000000">MessageSourceAware</span>, <span style="color:#000000">InitializingBean</span> {
<span style="color:#aa5500">//省略其他属性</span>
<span style="color:#770088">private</span> <span style="color:#000000">List</span><span style="color:#981a1a"><</span><span style="color:#000000">AuthenticationProvider</span><span style="color:#981a1a">></span> <span style="color:#000000">providers</span> <span style="color:#981a1a">=</span> <span style="color:#000000">Collections</span>.<span style="color:#000000">emptyList</span>();
<span style="color:#aa5500">//省略其他内容</span>
}</span></span>
认证提供者管理器,该类中维护了一个认证提供者列表,只要这个列表中的任何一个认证提供者提供的认证方式认证通过,认证就结束。
5. AuthenticationProvider
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">public</span> <span style="color:#770088">interface</span> <span style="color:#0000ff">AuthenticationProvider</span> {
<span style="color:#aa5500">/**</span>
<span style="color:#aa5500">* 执行认证,并返回认证结果</span>
<span style="color:#aa5500">*/</span>
<span style="color:#000000">Authentication</span> <span style="color:#000000">authenticate</span>(<span style="color:#000000">Authentication</span> <span style="color:#000000">authentication</span>) <span style="color:#770088">throws</span> <span style="color:#000000">AuthenticationException</span>;
<span style="color:#aa5500">/**</span>
<span style="color:#aa5500">* 支持认证的类型,用于实现自定义认证,比如手机号和短信登录认证需要用户自己来实现</span>
<span style="color:#aa5500">*/</span>
<span style="color:#008855">boolean</span> <span style="color:#000000">supports</span>(<span style="color:#000000">Class</span><span style="color:#981a1a"><?></span> <span style="color:#000000">authentication</span>);
}</span></span>
认证提供者,这是一个接口,具体如何认证,就看如何实现该接口。Spring Security 提供了 DaoAuthenticationProvider 实现该接口,这个类就是使用数据库中数据进行认证。
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">DaoAuthenticationProvider</span> <span style="color:#770088">extends</span> <span style="color:#000000">AbstractUserDetailsAuthenticationProvider</span> {
<span style="color:#aa5500">//省略其他属性</span>
<span style="color:#770088">private</span> <span style="color:#000000">PasswordEncoder</span> <span style="color:#000000">passwordEncoder</span>; <span style="color:#aa5500">//密码加密器,主要用于密码加密</span>
<span style="color:#770088">private</span> <span style="color:#000000">UserDetailsService</span> <span style="color:#000000">userDetailsService</span>; <span style="color:#aa5500">//用户详细信息服务,主要用于查询认证用户信息</span>
<span style="color:#aa5500">//省略其他内容</span>
}</span></span>
6. UserDetailsService
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">public</span> <span style="color:#770088">interface</span> <span style="color:#0000ff">UserDetailsService</span> {
<span style="color:#aa5500">/**</span>
<span style="color:#aa5500">* 根据用户名获取用户详细信息</span>
<span style="color:#aa5500">*/</span>
<span style="color:#000000">UserDetails</span> <span style="color:#000000">loadUserByUsername</span>(<span style="color:#008855">String</span> <span style="color:#000000">username</span>) <span style="color:#770088">throws</span> <span style="color:#000000">UsernameNotFoundException</span>;
}</span></span>
7. UserDetails
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">public</span> <span style="color:#770088">interface</span> <span style="color:#0000ff">UserDetails</span> <span style="color:#770088">extends</span> <span style="color:#000000">Serializable</span> {
<span style="color:#aa5500">/**</span>
<span style="color:#aa5500">* 用户拥有的权限列表</span>
<span style="color:#aa5500">*/</span>
<span style="color:#000000">Collection</span><span style="color:#981a1a"><?</span> <span style="color:#770088">extends</span> <span style="color:#000000">GrantedAuthority</span><span style="color:#981a1a">></span> <span style="color:#000000">getAuthorities</span>();
<span style="color:#aa5500">/**</span>
<span style="color:#aa5500">* 密码</span>
<span style="color:#aa5500">*/</span>
<span style="color:#008855">String</span> <span style="color:#000000">getPassword</span>();
<span style="color:#aa5500">/**</span>
<span style="color:#aa5500">* 账号</span>
<span style="color:#aa5500">*/</span>
<span style="color:#008855">String</span> <span style="color:#000000">getUsername</span>();
<span style="color:#aa5500">/**</span>
<span style="color:#aa5500">* 账号是否过期,过期的账号不能进行认证</span>
<span style="color:#aa5500">*/</span>
<span style="color:#008855">boolean</span> <span style="color:#000000">isAccountNonExpired</span>();
<span style="color:#aa5500">/**</span>
<span style="color:#aa5500">* 账号是否被锁定</span>
<span style="color:#aa5500">*/</span>
<span style="color:#008855">boolean</span> <span style="color:#000000">isAccountNonLocked</span>();
<span style="color:#aa5500">/**</span>
<span style="color:#aa5500">* 凭据是否过期,过期的凭据不能进行认证</span>
<span style="color:#aa5500">*/</span>
<span style="color:#008855">boolean</span> <span style="color:#000000">isCredentialsNonExpired</span>();
<span style="color:#aa5500">/**</span>
<span style="color:#aa5500">* 账号是否被启用,未启用的账号不能进行认证</span>
<span style="color:#aa5500">*/</span>
<span style="color:#008855">boolean</span> <span style="color:#000000">isEnabled</span>();
}</span></span>
8. SecurityContextHolder
SecurityContextHolder 是最基本的对象,它负责存储当前 SecurityContext 信息。SecurityContextHolder默认使用 ThreadLocal 来存储认证信息,意味着这是一种与线程绑定的策略。在Web场景下的使用Spring Security,在用户登录时自动绑定认证信息到当前线程,在用户退出时,自动清除当前线程的认证信息。
9. SecurityContext
SecurityContext 负责存储认证通过的用户信息(Authentication对象),保存着当前用户是什么,是否已经通过认证,拥有哪些权限等等。
10. AuthenticationSuccessHandler
AuthenticationSuccessHandler 主要用于认证成功后的处理,比如返回页面或者数据。
11. AuthenticationFailureHandler
AuthenticationFailureHandler 主要用于认证失败后的处理,比如返回页面或者数据。
12. AccessDecisionManager
AccessDecisionManager 主要用于实现权限,决定请求是否具有访问的权限。
13. AccessDeniedHandler
AccessDeniedHandler 主要用于无权访问时的处理
第三节 Spring Security 工作流程
1. DelegatingFilterProxy
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">DelegatingFilterProxy</span> <span style="color:#770088">extends</span> <span style="color:#000000">GenericFilterBean</span> {}
<span style="color:#770088">public</span> <span style="color:#770088">abstract</span> <span style="color:#770088">class</span> <span style="color:#0000ff">GenericFilterBean</span> <span style="color:#770088">implements</span> <span style="color:#000000">Filter</span>, <span style="color:#000000">BeanNameAware</span>, <span style="color:#000000">EnvironmentAware</span>,
<span style="color:#000000">EnvironmentCapable</span>, <span style="color:#000000">ServletContextAware</span>, <span style="color:#000000">InitializingBean</span>, <span style="color:#000000">DisposableBean</span> {}</span></span>
由上面的类定义可以看出,DelegatingFilterProxy
是一个 Filter
,同时,也是一个InitializingBean
。
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">public</span> <span style="color:#770088">interface</span> <span style="color:#0000ff">InitializingBean</span> {
<span style="color:#aa5500">/**</span>
<span style="color:#aa5500">* 当Bean的所有属性设置后由包含的BeanFactory调用,而BeanFactory就是用来创建bean的,换言之,就是将Bean纳入Spring IOC容器</span>
<span style="color:#aa5500">*/</span>
<span style="color:#008855">void</span> <span style="color:#000000">afterPropertiesSet</span>() <span style="color:#770088">throws</span> <span style="color:#000000">Exception</span>;
}</span></span>
实现了InitializingBean
接口的类,在创建对象并完成属性设置后,会被纳入Spring IOC 容器管理。如果DelegatingFilterProxy
在web.xml
中配置,那么,在容器启动时就会实例化该Filter
,然后完成初始化,随后被纳入 Spring IOC 容器管理。这样就相当于与 Spring 完成整合。
而 DelegatingFilterProxy
由 spring web 提供,与 Spring Security 无关。那么 DelegatingFilterProxy
到底有什么作用呢?
DelegatingFilterProxy
如何知道其所代理的Filter是哪个呢?
这是通过其自身的targetBeanName的属性来确定的,通过该名称,DelegatingFilterProxy
可以从WebApplicationContext
中获取指定的 bean
作为代理对象。该属性可以通过在web.xml
中定义 DelegatingFilterProxy
时通过 init-param
来指定,如果未指定,则将取其在web.xml
中声明时定义的名称作为 targetBeanName 的值。
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#aa5500"><!--委派过滤器,用于整合其他框架--></span>
<span style="color:#117700"><</span><span style="color:#117700">filter</span><span style="color:#117700">></span>
<span style="color:#aa5500"><!--整合spring security时,此过滤器的名称固定springSecurityFilterChain--></span>
<span style="color:#117700"><</span><span style="color:#117700">filter-name</span><span style="color:#117700">></span>springSecurityFilterChain<span style="color:#117700"></</span><span style="color:#117700">filter-name</span><span style="color:#117700">></span>
<span style="color:#117700"><</span><span style="color:#117700">filter-class</span><span style="color:#117700">></span>org.springframework.web.filter.DelegatingFilterProxy<span style="color:#117700"></</span><span style="color:#117700">filter-class</span><span style="color:#117700">></span>
<span style="color:#117700"><</span><span style="color:#117700">init-param</span><span style="color:#117700">></span>
<span style="color:#117700"><</span><span style="color:#117700">param-name</span><span style="color:#117700">></span>targetBeanName<span style="color:#117700"></</span><span style="color:#117700">param-name</span><span style="color:#117700">></span>
<span style="color:#117700"><</span><span style="color:#117700">param-value</span><span style="color:#117700">></span>springSecurityFilterChain<span style="color:#117700"></</span><span style="color:#117700">param-value</span><span style="color:#117700">></span>
<span style="color:#117700"></</span><span style="color:#117700">init-param</span><span style="color:#117700">></span>
<span style="color:#117700"></</span><span style="color:#117700">filter</span><span style="color:#117700">></span>
<span style="color:#117700"><</span><span style="color:#117700">filter-mapping</span><span style="color:#117700">></span>
<span style="color:#117700"><</span><span style="color:#117700">filter-name</span><span style="color:#117700">></span>springSecurityFilterChain<span style="color:#117700"></</span><span style="color:#117700">filter-name</span><span style="color:#117700">></span>
<span style="color:#117700"><</span><span style="color:#117700">url-pattern</span><span style="color:#117700">></span>/*<span style="color:#117700"></</span><span style="color:#117700">url-pattern</span><span style="color:#117700">></span>
<span style="color:#117700"></</span><span style="color:#117700">filter-mapping</span><span style="color:#117700">></span></span></span>
2. FilterChainProxy
使用Spring Security时,DelegatingFilterProxy 代理的就是一个 FilterChainProxy。当我们使用基于Spring Security的NameSpace进行配置时,系统会自动为我们注册一个名为 springSecurityFilterChain 类型为 FilterChainProxy 的 Bean,这也是为什么我们在使用 Spring Security 时需要在 web.xml
中声明一个 name 为 springSecurityFilterChain 的 DelegatingFilterProxy 的 Filter 了。
一个 FilterChainProxy 中可以包含有多个 FilterChain,但是某个请求只会对应一个 FilterChain,而一个 FilterChain 中又可以包含有多个 Filter。
而 Spring Security 底层正是通过一系列的 Filter 来工作的。具体详情如下:
2.1 WebAsyncManagerIntegrationFilter
将Security上下文与SpringWeb中用于处理异步请求映射的WebAsyncmanager进行集成
2.2 SecurityContextPersistenceFilter
在每次请求处理之前将该请求相关的安全上下文信息加载到SecurityContextHolder中,然后在该次请求处理完成之后麻将SecurityContextHolder中关于这次请求的信息存储的‘仓储’中,然后将SecurityContextHolder中的信息清除,例如在Session中维护一个用户的安全信息就是这个过滤器处理的
2.4 CsrfFilter
用于处理跨站请求伪造
2.5 LogoutFilter
用于处理退出登录
2.6 UsernamePasswordAuthenticationFilter
[重点]
用于处理基于表单的登录请求,从表单中获取用户名和密码,默认情况下处理来自/login的请求,从表单中获取用户名和密码, 默认使用表单name值为username和password,这两个值可以通过这个过滤器的usernaemparamter个passwordParameter连个参数的值进行修改
2.7 DefaultLoginPageGeneratingFilter
如果没有配置登陆页面,那系统初始化就会配置这个过滤器。并且用于在需要进行登陆时生成一个登陆表单页
2.8 BasicAuthenticationFilter
用于处理请求的缓存
2.10 SecurityContextHolderAwareRequestFilter
2.11 AnonymousAuthenticationFilter
检测SecurityContextHolder中是否存在Authentication对象,如果不存在为其提供一个匿名Authentication
2.13 ExceptionTranslationFilter
处理AccessDeniedException和AuthenticationException异常
2.14 FilterSecurityInterceptor
可以看作过滤器链的出口
2.15 RememberMeAuthenticationFilter
当用户没有登录而直接访问资源时,从cookie中找出用户的信息,如果SpringSecurity能够识别出用户提供remember me cookie ,用户将不必填写用户名和密码,而是直接登录进入系统,该过滤器默认从不开启
第三节 Spring Security 认证
1. 数据库认证
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">qf</span>.<span style="color:#000000">authentication</span>.<span style="color:#000000">config</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">context</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">Bean</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">authentication</span>.<span style="color:#000000">dao</span>.<span style="color:#000000">DaoAuthenticationProvider</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">config</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">authentication</span>.<span style="color:#000000">builders</span>.<span style="color:#000000">AuthenticationManagerBuilder</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">config</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">web</span>.<span style="color:#000000">builders</span>.<span style="color:#000000">HttpSecurity</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">config</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">web</span>.<span style="color:#000000">builders</span>.<span style="color:#000000">WebSecurity</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">config</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">web</span>.<span style="color:#000000">configuration</span>.<span style="color:#000000">EnableWebSecurity</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">config</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">web</span>.<span style="color:#000000">configuration</span>.<span style="color:#000000">WebSecurityConfigurerAdapter</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">crypto</span>.<span style="color:#000000">bcrypt</span>.<span style="color:#000000">BCryptPasswordEncoder</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">crypto</span>.<span style="color:#000000">password</span>.<span style="color:#000000">PasswordEncoder</span>;
<span style="color:#555555">@EnableWebSecurity</span> <span style="color:#aa5500">//启用security</span>
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">SecurityConfig</span> <span style="color:#770088">extends</span> <span style="color:#000000">WebSecurityConfigurerAdapter</span> {
<span style="color:#aa5500">//创建密码加密器,并纳入Spring IOC容器管理,该Bean的名字就是方法名</span>
<span style="color:#555555">@Bean</span>
<span style="color:#770088">public</span> <span style="color:#000000">PasswordEncoder</span> <span style="color:#000000">passwordEncoder</span>(){
<span style="color:#770088">return</span> <span style="color:#770088">new</span> <span style="color:#000000">BCryptPasswordEncoder</span>();
}
<span style="color:#aa5500">//认证管理器配置</span>
<span style="color:#555555">@Override</span>
<span style="color:#770088">protected</span> <span style="color:#008855">void</span> <span style="color:#000000">configure</span>(<span style="color:#000000">AuthenticationManagerBuilder</span> <span style="color:#000000">auth</span>) <span style="color:#770088">throws</span> <span style="color:#000000">Exception</span> {
<span style="color:#aa5500">//数据库数据认证提供器</span>
<span style="color:#000000">DaoAuthenticationProvider</span> <span style="color:#000000">daoAuthenticationProvider</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">DaoAuthenticationProvider</span>();
<span style="color:#aa5500">//设置认证使用的用户详情服务,业就是查询用户信息的服务</span>
<span style="color:#000000">daoAuthenticationProvider</span>.<span style="color:#000000">setUserDetailsService</span>();
<span style="color:#aa5500">//设置密码使用的加密器</span>
<span style="color:#000000">daoAuthenticationProvider</span>.<span style="color:#000000">setPasswordEncoder</span>(<span style="color:#000000">passwordEncoder</span>());
<span style="color:#aa5500">//设置认证管理构建器使用的认证提供器</span>
<span style="color:#000000">auth</span>.<span style="color:#000000">authenticationProvider</span>(<span style="color:#000000">daoAuthenticationProvider</span>);
}
}</span></span>
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">qf</span>.<span style="color:#000000">authentication</span>.<span style="color:#000000">service</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">core</span>.<span style="color:#000000">userdetails</span>.<span style="color:#000000">UserDetailsService</span>;
<span style="color:#aa5500">//用户业务层,继承了UserDetailsService,方便与security结合</span>
<span style="color:#770088">public</span> <span style="color:#770088">interface</span> <span style="color:#0000ff">UserService</span> <span style="color:#770088">extends</span> <span style="color:#000000">UserDetailsService</span> {
}
<span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">qf</span>.<span style="color:#000000">authentication</span>.<span style="color:#000000">service</span>.<span style="color:#000000">impl</span>;
<span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">qf</span>.<span style="color:#000000">authentication</span>.<span style="color:#000000">service</span>.<span style="color:#000000">UserService</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">core</span>.<span style="color:#000000">userdetails</span>.<span style="color:#000000">UserDetails</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">core</span>.<span style="color:#000000">userdetails</span>.<span style="color:#000000">UsernameNotFoundException</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">stereotype</span>.<span style="color:#000000">Service</span>;
<span style="color:#555555">@Service</span>
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">UserServiceImpl</span> <span style="color:#770088">implements</span> <span style="color:#000000">UserService</span> {
<span style="color:#555555">@Override</span>
<span style="color:#770088">public</span> <span style="color:#000000">UserDetails</span> <span style="color:#000000">loadUserByUsername</span>(<span style="color:#008855">String</span> <span style="color:#000000">username</span>) <span style="color:#770088">throws</span> <span style="color:#000000">UsernameNotFoundException</span> {
<span style="color:#770088">return</span> <span style="color:#221199">null</span>;
}
}</span></span>
1.4 创建用户实体
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">qf</span>.<span style="color:#000000">authentication</span>.<span style="color:#000000">model</span>;
<span style="color:#770088">import</span> <span style="color:#000000">lombok</span>.<span style="color:#000000">Data</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">core</span>.<span style="color:#000000">authority</span>.<span style="color:#000000">SimpleGrantedAuthority</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">core</span>.<span style="color:#000000">userdetails</span>.<span style="color:#000000">UserDetails</span>;
<span style="color:#770088">import</span> <span style="color:#000000">java</span>.<span style="color:#000000">util</span>.<span style="color:#000000">List</span>;
<span style="color:#555555">@Data</span>
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">User</span> <span style="color:#770088">implements</span> <span style="color:#000000">UserDetails</span> {
<span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">username</span>; <span style="color:#aa5500">//账号</span>
<span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">password</span>; <span style="color:#aa5500">//密码</span>
<span style="color:#770088">private</span> <span style="color:#000000">List</span><span style="color:#981a1a"><</span><span style="color:#000000">SimpleGrantedAuthority</span><span style="color:#981a1a">></span> <span style="color:#000000">authorities</span>; <span style="color:#aa5500">//拥有的权限</span>
<span style="color:#555555">@Override</span>
<span style="color:#770088">public</span> <span style="color:#008855">boolean</span> <span style="color:#000000">isAccountNonExpired</span>() { <span style="color:#aa5500">//账号是否未过期</span>
<span style="color:#770088">return</span> <span style="color:#221199">true</span>;
}
<span style="color:#555555">@Override</span>
<span style="color:#770088">public</span> <span style="color:#008855">boolean</span> <span style="color:#000000">isAccountNonLocked</span>() { <span style="color:#aa5500">//账号是否未被锁定</span>
<span style="color:#770088">return</span> <span style="color:#221199">true</span>;
}
<span style="color:#555555">@Override</span>
<span style="color:#770088">public</span> <span style="color:#008855">boolean</span> <span style="color:#000000">isCredentialsNonExpired</span>() {<span style="color:#aa5500">//凭据是否未过期</span>
<span style="color:#770088">return</span> <span style="color:#221199">true</span>;
}
<span style="color:#555555">@Override</span>
<span style="color:#770088">public</span> <span style="color:#008855">boolean</span> <span style="color:#000000">isEnabled</span>() {<span style="color:#aa5500">//账号是否可用</span>
<span style="color:#770088">return</span> <span style="color:#221199">true</span>;
}
}</span></span>
1.5 完善用户信息服务
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#555555">@Override</span>
<span style="color:#770088">public</span> <span style="color:#000000">UserDetails</span> <span style="color:#0000ff">loadUserByUsername</span>(<span style="color:#008855">String</span> <span style="color:#000000">username</span>) <span style="color:#770088">throws</span> <span style="color:#000000">UsernameNotFoundException</span> {
<span style="color:#000000">User</span> <span style="color:#000000">user</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">User</span>();
<span style="color:#000000">user</span>.<span style="color:#000000">setUsername</span>(<span style="color:#aa1111">"admin"</span>);
<span style="color:#000000">user</span>.<span style="color:#000000">setPassword</span>(<span style="color:#000000">passwordEncoder</span>.<span style="color:#000000">encode</span>(<span style="color:#aa1111">"123456"</span>));
<span style="color:#000000">user</span>.<span style="color:#000000">setAuthorities</span>(<span style="color:#000000">Arrays</span>.<span style="color:#000000">asList</span>(<span style="color:#770088">new</span> <span style="color:#000000">SimpleGrantedAuthority</span>(<span style="color:#aa1111">"ROLE_ADMIN"</span>), <span style="color:#770088">new</span> <span style="color:#000000">SimpleGrantedAuthority</span>(<span style="color:#aa1111">"ROLE_USER"</span>)));
<span style="color:#770088">return</span> <span style="color:#000000">user</span>;
}</span></span>
1.6 完善认证管理器配置
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#aa5500">//认证管理器配置</span>
<span style="color:#555555">@Override</span>
<span style="color:#770088">protected</span> <span style="color:#008855">void</span> <span style="color:#0000ff">configure</span>(<span style="color:#000000">AuthenticationManagerBuilder</span> <span style="color:#000000">auth</span>) <span style="color:#770088">throws</span> <span style="color:#000000">Exception</span> {
<span style="color:#aa5500">//数据库数据认证提供器</span>
<span style="color:#000000">DaoAuthenticationProvider</span> <span style="color:#000000">daoAuthenticationProvider</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">DaoAuthenticationProvider</span>();
<span style="color:#aa5500">//设置认证使用的用户详情服务,业就是查询用户信息的服务</span>
<span style="color:#000000">daoAuthenticationProvider</span>.<span style="color:#000000">setUserDetailsService</span>(<span style="color:#000000">userService</span>);
<span style="color:#aa5500">//设置密码使用的加密器</span>
<span style="color:#000000">daoAuthenticationProvider</span>.<span style="color:#000000">setPasswordEncoder</span>(<span style="color:#000000">passwordEncoder</span>());
<span style="color:#aa5500">//设置认证管理构建器使用的认证提供器</span>
<span style="color:#000000">auth</span>.<span style="color:#000000">authenticationProvider</span>(<span style="color:#000000">daoAuthenticationProvider</span>);
}</span></span>
1.7 HTTP认证配置
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">qf</span>.<span style="color:#000000">authentication</span>.<span style="color:#000000">config</span>;
<span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">qf</span>.<span style="color:#000000">authentication</span>.<span style="color:#000000">service</span>.<span style="color:#000000">UserService</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">beans</span>.<span style="color:#000000">factory</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">Autowired</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">context</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">Bean</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">authentication</span>.<span style="color:#000000">dao</span>.<span style="color:#000000">DaoAuthenticationProvider</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">config</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">authentication</span>.<span style="color:#000000">builders</span>.<span style="color:#000000">AuthenticationManagerBuilder</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">config</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">web</span>.<span style="color:#000000">builders</span>.<span style="color:#000000">HttpSecurity</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">config</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">web</span>.<span style="color:#000000">builders</span>.<span style="color:#000000">WebSecurity</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">config</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">web</span>.<span style="color:#000000">configuration</span>.<span style="color:#000000">EnableWebSecurity</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">config</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">web</span>.<span style="color:#000000">configuration</span>.<span style="color:#000000">WebSecurityConfigurerAdapter</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">crypto</span>.<span style="color:#000000">bcrypt</span>.<span style="color:#000000">BCryptPasswordEncoder</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">crypto</span>.<span style="color:#000000">password</span>.<span style="color:#000000">PasswordEncoder</span>;
<span style="color:#555555">@EnableWebSecurity</span> <span style="color:#aa5500">//启用security</span>
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">SecurityConfig</span> <span style="color:#770088">extends</span> <span style="color:#000000">WebSecurityConfigurerAdapter</span> {
<span style="color:#555555">@Autowired</span>
<span style="color:#770088">private</span> <span style="color:#000000">UserService</span> <span style="color:#000000">userService</span>;
<span style="color:#aa5500">//创建密码加密器,并纳入Spring IOC容器管理,该Bean的名字就是方法名</span>
<span style="color:#555555">@Bean</span>
<span style="color:#770088">public</span> <span style="color:#000000">PasswordEncoder</span> <span style="color:#000000">passwordEncoder</span>(){
<span style="color:#770088">return</span> <span style="color:#770088">new</span> <span style="color:#000000">BCryptPasswordEncoder</span>();
}
<span style="color:#aa5500">//认证管理器配置</span>
<span style="color:#555555">@Override</span>
<span style="color:#770088">protected</span> <span style="color:#008855">void</span> <span style="color:#000000">configure</span>(<span style="color:#000000">AuthenticationManagerBuilder</span> <span style="color:#000000">auth</span>) <span style="color:#770088">throws</span> <span style="color:#000000">Exception</span> {
<span style="color:#aa5500">//数据库数据认证提供器</span>
<span style="color:#000000">DaoAuthenticationProvider</span> <span style="color:#000000">daoAuthenticationProvider</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">DaoAuthenticationProvider</span>();
<span style="color:#aa5500">//设置认证使用的用户详情服务,业就是查询用户信息的服务</span>
<span style="color:#000000">daoAuthenticationProvider</span>.<span style="color:#000000">setUserDetailsService</span>(<span style="color:#000000">userService</span>);
<span style="color:#aa5500">//设置密码使用的加密器</span>
<span style="color:#000000">daoAuthenticationProvider</span>.<span style="color:#000000">setPasswordEncoder</span>(<span style="color:#000000">passwordEncoder</span>());
<span style="color:#aa5500">//设置认证管理构建器使用的认证提供器</span>
<span style="color:#000000">auth</span>.<span style="color:#000000">authenticationProvider</span>(<span style="color:#000000">daoAuthenticationProvider</span>);
}
<span style="color:#aa5500">//Http认证配置</span>
<span style="color:#555555">@Override</span>
<span style="color:#770088">protected</span> <span style="color:#008855">void</span> <span style="color:#000000">configure</span>(<span style="color:#000000">HttpSecurity</span> <span style="color:#000000">http</span>) <span style="color:#770088">throws</span> <span style="color:#000000">Exception</span> {
<span style="color:#000000">http</span>.<span style="color:#000000">csrf</span>().<span style="color:#000000">disable</span>();<span style="color:#aa5500">//关闭跨站请求模拟</span>
<span style="color:#aa5500">//设置表单登录使用的登录地址、登录请求的URL地址、登录成功和失败分别使用的处理器 permitAll表示该操作不需要security的权限控制</span>
<span style="color:#000000">http</span>.<span style="color:#000000">formLogin</span>().<span style="color:#000000">loginPage</span>(<span style="color:#aa1111">"/"</span>).<span style="color:#000000">loginProcessingUrl</span>(<span style="color:#aa1111">"/login"</span>)
.<span style="color:#000000">successHandler</span>().<span style="color:#000000">failureHandler</span>().<span style="color:#000000">permitAll</span>();
<span style="color:#000000">http</span>.<span style="color:#000000">authorizeRequests</span>().<span style="color:#000000">anyRequest</span>().<span style="color:#000000">authenticated</span>();
<span style="color:#aa5500">//设置退出操作使当前session失效 permitAll表示该操作不需要security的权限控制</span>
<span style="color:#000000">http</span>.<span style="color:#000000">logout</span>().<span style="color:#000000">invalidateHttpSession</span>(<span style="color:#221199">true</span>).<span style="color:#000000">permitAll</span>();
}
}
</span></span>
1.8 创建认证处理器
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">qf</span>.<span style="color:#000000">authentication</span>.<span style="color:#000000">handler</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">core</span>.<span style="color:#000000">Authentication</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">web</span>.<span style="color:#000000">authentication</span>.<span style="color:#000000">AuthenticationSuccessHandler</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">stereotype</span>.<span style="color:#000000">Component</span>;
<span style="color:#770088">import</span> <span style="color:#000000">javax</span>.<span style="color:#000000">servlet</span>.<span style="color:#000000">ServletException</span>;
<span style="color:#770088">import</span> <span style="color:#000000">javax</span>.<span style="color:#000000">servlet</span>.<span style="color:#000000">http</span>.<span style="color:#000000">HttpServletRequest</span>;
<span style="color:#770088">import</span> <span style="color:#000000">javax</span>.<span style="color:#000000">servlet</span>.<span style="color:#000000">http</span>.<span style="color:#000000">HttpServletResponse</span>;
<span style="color:#770088">import</span> <span style="color:#000000">java</span>.<span style="color:#000000">io</span>.<span style="color:#000000">IOException</span>;
<span style="color:#aa5500">//认证成功的处理器</span>
<span style="color:#555555">@Component</span>
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">LoginSuccessHandler</span> <span style="color:#770088">implements</span> <span style="color:#000000">AuthenticationSuccessHandler</span> {
<span style="color:#555555">@Override</span>
<span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">onAuthenticationSuccess</span>(<span style="color:#000000">HttpServletRequest</span> <span style="color:#000000">request</span>, <span style="color:#000000">HttpServletResponse</span> <span style="color:#000000">response</span>, <span style="color:#000000">Authentication</span> <span style="color:#000000">authentication</span>) <span style="color:#770088">throws</span> <span style="color:#000000">IOException</span>, <span style="color:#000000">ServletException</span> {
<span style="color:#000000">response</span>.<span style="color:#000000">sendRedirect</span>(<span style="color:#aa1111">"/main.html"</span>);
}
}
<span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">qf</span>.<span style="color:#000000">authentication</span>.<span style="color:#000000">handler</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">core</span>.<span style="color:#000000">AuthenticationException</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">web</span>.<span style="color:#000000">authentication</span>.<span style="color:#000000">AuthenticationFailureHandler</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">stereotype</span>.<span style="color:#000000">Component</span>;
<span style="color:#770088">import</span> <span style="color:#000000">javax</span>.<span style="color:#000000">servlet</span>.<span style="color:#000000">ServletException</span>;
<span style="color:#770088">import</span> <span style="color:#000000">javax</span>.<span style="color:#000000">servlet</span>.<span style="color:#000000">http</span>.<span style="color:#000000">HttpServletRequest</span>;
<span style="color:#770088">import</span> <span style="color:#000000">javax</span>.<span style="color:#000000">servlet</span>.<span style="color:#000000">http</span>.<span style="color:#000000">HttpServletResponse</span>;
<span style="color:#770088">import</span> <span style="color:#000000">java</span>.<span style="color:#000000">io</span>.<span style="color:#000000">IOException</span>;
<span style="color:#aa5500">//认证失败的处理器</span>
<span style="color:#555555">@Component</span>
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">LoginFailureHandler</span> <span style="color:#770088">implements</span> <span style="color:#000000">AuthenticationFailureHandler</span> {
<span style="color:#555555">@Override</span>
<span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">onAuthenticationFailure</span>(<span style="color:#000000">HttpServletRequest</span> <span style="color:#000000">request</span>, <span style="color:#000000">HttpServletResponse</span> <span style="color:#000000">response</span>, <span style="color:#000000">AuthenticationException</span> <span style="color:#000000">exception</span>) <span style="color:#770088">throws</span> <span style="color:#000000">IOException</span>, <span style="color:#000000">ServletException</span> {
<span style="color:#000000">response</span>.<span style="color:#000000">sendRedirect</span>(<span style="color:#aa1111">"/"</span>);
}
}</span></span>
1.9 完善HTTP认证配置
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#aa5500">//Http认证配置</span>
<span style="color:#555555">@Override</span>
<span style="color:#770088">protected</span> <span style="color:#008855">void</span> <span style="color:#0000ff">configure</span>(<span style="color:#000000">HttpSecurity</span> <span style="color:#000000">http</span>) <span style="color:#770088">throws</span> <span style="color:#000000">Exception</span> {
<span style="color:#000000">http</span>.<span style="color:#000000">csrf</span>().<span style="color:#000000">disable</span>();<span style="color:#aa5500">//关闭跨站请求模拟</span>
<span style="color:#aa5500">//设置表单登录使用的登录地址、登录请求的URL地址、登录成功和失败分别使用的处理器 permitAll表示该操作不需要security的权限控制</span>
<span style="color:#000000">http</span>.<span style="color:#000000">formLogin</span>().<span style="color:#000000">loginPage</span>(<span style="color:#aa1111">"/"</span>).<span style="color:#000000">loginProcessingUrl</span>(<span style="color:#aa1111">"/login"</span>)
.<span style="color:#000000">successHandler</span>(<span style="color:#000000">loginSuccessHandler</span>).<span style="color:#000000">failureHandler</span>(<span style="color:#000000">loginFailureHandler</span>).<span style="color:#000000">permitAll</span>();
<span style="color:#000000">http</span>.<span style="color:#000000">authorizeRequests</span>().<span style="color:#000000">anyRequest</span>().<span style="color:#000000">authenticated</span>();
<span style="color:#aa5500">//设置退出操作使当前session失效 permitAll表示该操作不需要security的权限控制</span>
<span style="color:#000000">http</span>.<span style="color:#000000">logout</span>().<span style="color:#000000">invalidateHttpSession</span>(<span style="color:#221199">true</span>).<span style="color:#000000">permitAll</span>();
}</span></span>
1.10 页面创建
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#555555"><!DOCTYPE html></span>
<span style="color:#117700"><</span><span style="color:#117700">html</span> <span style="color:#0000cc">lang</span>=<span style="color:#aa1111">"en"</span><span style="color:#117700">></span>
<span style="color:#117700"><</span><span style="color:#117700">head</span><span style="color:#117700">></span>
<span style="color:#117700"><</span><span style="color:#117700">meta</span> <span style="color:#0000cc">charset</span>=<span style="color:#aa1111">"UTF-8"</span><span style="color:#117700">></span>
<span style="color:#117700"><</span><span style="color:#117700">title</span><span style="color:#117700">></span>Security登录<span style="color:#117700"></</span><span style="color:#117700">title</span><span style="color:#117700">></span>
<span style="color:#117700"></</span><span style="color:#117700">head</span><span style="color:#117700">></span>
<span style="color:#117700"><</span><span style="color:#117700">body</span><span style="color:#117700">></span>
<span style="color:#117700"><</span><span style="color:#117700">form</span> <span style="color:#0000cc">action</span>=<span style="color:#aa1111">"login"</span> <span style="color:#0000cc">method</span>=<span style="color:#aa1111">"post"</span><span style="color:#117700">></span>
<span style="color:#117700"><</span><span style="color:#117700">input</span> <span style="color:#0000cc">type</span>=<span style="color:#aa1111">"text"</span> <span style="color:#0000cc">name</span>=<span style="color:#aa1111">"username"</span><span style="color:#117700">></span>
<span style="color:#117700"><</span><span style="color:#117700">input</span> <span style="color:#0000cc">type</span>=<span style="color:#aa1111">"password"</span> <span style="color:#0000cc">name</span>=<span style="color:#aa1111">"password"</span><span style="color:#117700">></span>
<span style="color:#117700"><</span><span style="color:#117700">input</span> <span style="color:#0000cc">type</span>=<span style="color:#aa1111">"submit"</span> <span style="color:#0000cc">value</span>=<span style="color:#aa1111">"登录"</span><span style="color:#117700">></span>
<span style="color:#117700"></</span><span style="color:#117700">form</span><span style="color:#117700">></span>
<span style="color:#117700"></</span><span style="color:#117700">body</span><span style="color:#117700">></span>
<span style="color:#117700"></</span><span style="color:#117700">html</span><span style="color:#117700">></span></span></span>
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#555555"><!DOCTYPE html></span>
<span style="color:#117700"><</span><span style="color:#117700">html</span> <span style="color:#0000cc">lang</span>=<span style="color:#aa1111">"en"</span><span style="color:#117700">></span>
<span style="color:#117700"><</span><span style="color:#117700">head</span><span style="color:#117700">></span>
<span style="color:#117700"><</span><span style="color:#117700">meta</span> <span style="color:#0000cc">charset</span>=<span style="color:#aa1111">"UTF-8"</span><span style="color:#117700">></span>
<span style="color:#117700"><</span><span style="color:#117700">title</span><span style="color:#117700">></span>Security登录成功<span style="color:#117700"></</span><span style="color:#117700">title</span><span style="color:#117700">></span>
<span style="color:#117700"></</span><span style="color:#117700">head</span><span style="color:#117700">></span>
<span style="color:#117700"><</span><span style="color:#117700">body</span><span style="color:#117700">></span>
认证通过了
<span style="color:#117700"></</span><span style="color:#117700">body</span><span style="color:#117700">></span>
<span style="color:#117700"></</span><span style="color:#117700">html</span><span style="color:#117700">></span></span></span>
登录请求被 UsernamePasswordAuthenticationFilter 拦截,该拦截器尝试认证,认证过程中调用 AuthenticationManager进行认证。AuthenticationManager进行认证时,将该认证管理器中的所有认证提供器遍历一遍,遍历过程中,首先检测认证提供器是否支持认证的票据类型,如果支持,则认证提供器开始进行认证。认证提供器认证过程中会调用 UserDetailsService 获取用户信息,然后进行信息比对,如果正确,则返回一个认证通过的票据。所有认证提供器中,只要任意一个认证提供器认证通过,则表示认证成功。
2. 短信认证
2.1 创建短信认证过滤器
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">qf</span>.<span style="color:#000000">authentication</span>.<span style="color:#000000">sms</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">lang</span>.<span style="color:#000000">Nullable</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">authentication</span>.<span style="color:#000000">AuthenticationManager</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">core</span>.<span style="color:#000000">Authentication</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">core</span>.<span style="color:#000000">AuthenticationException</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">web</span>.<span style="color:#000000">authentication</span>.<span style="color:#000000">AbstractAuthenticationProcessingFilter</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">web</span>.<span style="color:#000000">util</span>.<span style="color:#000000">matcher</span>.<span style="color:#000000">AntPathRequestMatcher</span>;
<span style="color:#770088">import</span> <span style="color:#000000">javax</span>.<span style="color:#000000">servlet</span>.<span style="color:#000000">ServletException</span>;
<span style="color:#770088">import</span> <span style="color:#000000">javax</span>.<span style="color:#000000">servlet</span>.<span style="color:#000000">http</span>.<span style="color:#000000">HttpServletRequest</span>;
<span style="color:#770088">import</span> <span style="color:#000000">javax</span>.<span style="color:#000000">servlet</span>.<span style="color:#000000">http</span>.<span style="color:#000000">HttpServletResponse</span>;
<span style="color:#770088">import</span> <span style="color:#000000">java</span>.<span style="color:#000000">io</span>.<span style="color:#000000">IOException</span>;
<span style="color:#aa5500">//短信认证提供器,模仿UsernamePasswordAuthenticationFilter编写</span>
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">SmsAuthenticationFilter</span> <span style="color:#770088">extends</span> <span style="color:#000000">AbstractAuthenticationProcessingFilter</span> {
<span style="color:#aa5500">//短信登录使用的URL,请求类型必须时POST</span>
<span style="color:#770088">private</span> <span style="color:#770088">static</span> <span style="color:#770088">final</span> <span style="color:#000000">AntPathRequestMatcher</span> <span style="color:#000000">DEFAULT_ANT_PATH_REQUEST_MATCHER</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">AntPathRequestMatcher</span>(<span style="color:#aa1111">"/sms"</span>,<span style="color:#aa1111">"POST"</span>);
<span style="color:#770088">public</span> <span style="color:#000000">SmsAuthenticationFilter</span>() {
<span style="color:#770088">super</span>(<span style="color:#000000">DEFAULT_ANT_PATH_REQUEST_MATCHER</span>);
}
<span style="color:#770088">public</span> <span style="color:#000000">SmsAuthenticationFilter</span>(<span style="color:#000000">AuthenticationManager</span> <span style="color:#000000">authenticationManager</span>) {
<span style="color:#770088">super</span>(<span style="color:#000000">DEFAULT_ANT_PATH_REQUEST_MATCHER</span>, <span style="color:#000000">authenticationManager</span>);
}
<span style="color:#aa5500">//尝试认证</span>
<span style="color:#555555">@Override</span>
<span style="color:#770088">public</span> <span style="color:#000000">Authentication</span> <span style="color:#000000">attemptAuthentication</span>(<span style="color:#000000">HttpServletRequest</span> <span style="color:#000000">request</span>, <span style="color:#000000">HttpServletResponse</span> <span style="color:#000000">response</span>)
<span style="color:#770088">throws</span> <span style="color:#000000">AuthenticationException</span>, <span style="color:#000000">IOException</span>, <span style="color:#000000">ServletException</span> {
<span style="color:#770088">return</span> <span style="color:#221199">null</span>;
}
<span style="color:#aa5500">//获取短信验证码</span>
<span style="color:#555555">@Nullable</span>
<span style="color:#770088">protected</span> <span style="color:#008855">String</span> <span style="color:#000000">obtainCode</span>(<span style="color:#000000">HttpServletRequest</span> <span style="color:#000000">request</span>) {
<span style="color:#770088">return</span> <span style="color:#000000">request</span>.<span style="color:#000000">getParameter</span>(<span style="color:#aa1111">"code"</span>);
}
<span style="color:#aa5500">//获取手机号码</span>
<span style="color:#555555">@Nullable</span>
<span style="color:#770088">protected</span> <span style="color:#008855">String</span> <span style="color:#000000">obtainMobile</span>(<span style="color:#000000">HttpServletRequest</span> <span style="color:#000000">request</span>) {
<span style="color:#770088">return</span> <span style="color:#000000">request</span>.<span style="color:#000000">getParameter</span>(<span style="color:#aa1111">"mobile"</span>);
}
}</span></span>
2.2 创建短信认证票据
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">qf</span>.<span style="color:#000000">authentication</span>.<span style="color:#000000">sms</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">authentication</span>.<span style="color:#000000">AbstractAuthenticationToken</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">core</span>.<span style="color:#000000">GrantedAuthority</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">core</span>.<span style="color:#000000">SpringSecurityCoreVersion</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">util</span>.<span style="color:#000000">Assert</span>;
<span style="color:#770088">import</span> <span style="color:#000000">java</span>.<span style="color:#000000">util</span>.<span style="color:#000000">Collection</span>;
<span style="color:#aa5500">//短信认证的票据</span>
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">SmsAuthenticationToken</span> <span style="color:#770088">extends</span> <span style="color:#000000">AbstractAuthenticationToken</span> {
<span style="color:#770088">private</span> <span style="color:#770088">static</span> <span style="color:#770088">final</span> <span style="color:#008855">long</span> <span style="color:#000000">serialVersionUID</span> <span style="color:#981a1a">=</span> <span style="color:#000000">SpringSecurityCoreVersion</span>.<span style="color:#000000">SERIAL_VERSION_UID</span>;
<span style="color:#aa5500">//认证之前存储手机号码,认证之后存储的是用户信息,也就是一个User对象</span>
<span style="color:#770088">private</span> <span style="color:#770088">final</span> <span style="color:#008855">Object</span> <span style="color:#000000">principal</span>;
<span style="color:#aa5500">//验证码</span>
<span style="color:#770088">private</span> <span style="color:#008855">Object</span> <span style="color:#000000">credentials</span>;
<span style="color:#aa5500">/**</span>
<span style="color:#aa5500">* 认证之前使用</span>
<span style="color:#aa5500">* @param principal</span>
<span style="color:#aa5500">*/</span>
<span style="color:#770088">public</span> <span style="color:#000000">SmsAuthenticationToken</span>(<span style="color:#008855">Object</span> <span style="color:#000000">principal</span>, <span style="color:#008855">Object</span> <span style="color:#000000">credentials</span>){
<span style="color:#770088">super</span>(<span style="color:#221199">null</span>);
<span style="color:#770088">this</span>.<span style="color:#000000">principal</span> <span style="color:#981a1a">=</span> <span style="color:#000000">principal</span>;
<span style="color:#770088">this</span>.<span style="color:#000000">credentials</span> <span style="color:#981a1a">=</span> <span style="color:#000000">credentials</span>;
<span style="color:#770088">super</span>.<span style="color:#000000">setAuthenticated</span>(<span style="color:#221199">false</span>);
}
<span style="color:#aa5500">/**</span>
<span style="color:#aa5500">* 认证之后使用</span>
<span style="color:#aa5500">* @param principal</span>
<span style="color:#aa5500">* @param authorities</span>
<span style="color:#aa5500">*/</span>
<span style="color:#770088">public</span> <span style="color:#000000">SmsAuthenticationToken</span>(<span style="color:#008855">Object</span> <span style="color:#000000">principal</span>, <span style="color:#008855">Object</span> <span style="color:#000000">credentials</span>, <span style="color:#000000">Collection</span><span style="color:#981a1a"><?</span> <span style="color:#770088">extends</span> <span style="color:#000000">GrantedAuthority</span><span style="color:#981a1a">></span> <span style="color:#000000">authorities</span>) {
<span style="color:#770088">super</span>(<span style="color:#000000">authorities</span>);
<span style="color:#770088">this</span>.<span style="color:#000000">principal</span> <span style="color:#981a1a">=</span> <span style="color:#000000">principal</span>;
<span style="color:#770088">this</span>.<span style="color:#000000">credentials</span> <span style="color:#981a1a">=</span> <span style="color:#000000">credentials</span>;
<span style="color:#770088">super</span>.<span style="color:#000000">setAuthenticated</span>(<span style="color:#221199">true</span>);
}
<span style="color:#555555">@Override</span>
<span style="color:#770088">public</span> <span style="color:#008855">Object</span> <span style="color:#000000">getCredentials</span>() {
<span style="color:#770088">return</span> <span style="color:#000000">credentials</span>;
}
<span style="color:#555555">@Override</span>
<span style="color:#770088">public</span> <span style="color:#008855">Object</span> <span style="color:#000000">getPrincipal</span>() {
<span style="color:#770088">return</span> <span style="color:#000000">principal</span>;
}
<span style="color:#aa5500">//这个方法是security框架执行认证流程时调用的,用户不应该调用,应该使用构造方法完成认证</span>
<span style="color:#555555">@Override</span>
<span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">setAuthenticated</span>(<span style="color:#008855">boolean</span> <span style="color:#000000">isAuthenticated</span>) <span style="color:#770088">throws</span> <span style="color:#000000">IllegalArgumentException</span> {
<span style="color:#000000">Assert</span>.<span style="color:#000000">isTrue</span>(<span style="color:#981a1a">!</span><span style="color:#000000">isAuthenticated</span>,
<span style="color:#aa1111">"Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead"</span>);
<span style="color:#770088">super</span>.<span style="color:#000000">setAuthenticated</span>(<span style="color:#221199">false</span>);
}
<span style="color:#555555">@Override</span>
<span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">eraseCredentials</span>() {
<span style="color:#770088">super</span>.<span style="color:#000000">eraseCredentials</span>();
<span style="color:#770088">this</span>.<span style="color:#000000">credentials</span> <span style="color:#981a1a">=</span> <span style="color:#221199">null</span>;
}
}</span></span>
2.3 创建短信实体
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">qf</span>.<span style="color:#000000">authentication</span>.<span style="color:#000000">sms</span>;
<span style="color:#770088">import</span> <span style="color:#000000">lombok</span>.<span style="color:#000000">AllArgsConstructor</span>;
<span style="color:#770088">import</span> <span style="color:#000000">lombok</span>.<span style="color:#000000">Data</span>;
<span style="color:#770088">import</span> <span style="color:#000000">lombok</span>.<span style="color:#000000">NoArgsConstructor</span>;
<span style="color:#555555">@Data</span>
<span style="color:#555555">@AllArgsConstructor</span>
<span style="color:#555555">@NoArgsConstructor</span>
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">SmsCode</span> {
<span style="color:#aa5500">//手机号</span>
<span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">mobile</span>;
<span style="color:#aa5500">//验证码</span>
<span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">code</span>;
<span style="color:#aa5500">//过期时间</span>
<span style="color:#770088">private</span> <span style="color:#008855">long</span> <span style="color:#000000">expire</span>;
}</span></span>
2.4 短信模拟
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">qf</span>.<span style="color:#000000">authentication</span>.<span style="color:#000000">controller</span>;
<span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">qf</span>.<span style="color:#000000">authentication</span>.<span style="color:#000000">sms</span>.<span style="color:#000000">SmsCode</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">stereotype</span>.<span style="color:#000000">Controller</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">web</span>.<span style="color:#000000">bind</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">GetMapping</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">web</span>.<span style="color:#000000">bind</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">RequestParam</span>;
<span style="color:#770088">import</span> <span style="color:#000000">javax</span>.<span style="color:#000000">imageio</span>.<span style="color:#000000">ImageIO</span>;
<span style="color:#770088">import</span> <span style="color:#000000">javax</span>.<span style="color:#000000">servlet</span>.<span style="color:#000000">http</span>.<span style="color:#000000">HttpServletResponse</span>;
<span style="color:#770088">import</span> <span style="color:#000000">javax</span>.<span style="color:#000000">servlet</span>.<span style="color:#000000">http</span>.<span style="color:#000000">HttpSession</span>;
<span style="color:#770088">import</span> <span style="color:#000000">java</span>.<span style="color:#000000">awt</span>.<span style="color:#981a1a">*</span>;
<span style="color:#770088">import</span> <span style="color:#000000">java</span>.<span style="color:#000000">awt</span>.<span style="color:#000000">image</span>.<span style="color:#000000">BufferedImage</span>;
<span style="color:#770088">import</span> <span style="color:#000000">java</span>.<span style="color:#000000">io</span>.<span style="color:#000000">IOException</span>;
<span style="color:#770088">import</span> <span style="color:#000000">java</span>.<span style="color:#000000">util</span>.<span style="color:#000000">Random</span>;
<span style="color:#555555">@Controller</span>
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">SmsController</span> {
<span style="color:#555555">@GetMapping</span>(<span style="color:#aa1111">"/code"</span>)
<span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">imgCode</span>(<span style="color:#555555">@RequestParam</span>(<span style="color:#aa1111">"mobile"</span>)<span style="color:#008855">String</span> <span style="color:#000000">mobile</span>, <span style="color:#000000">HttpSession</span> <span style="color:#000000">session</span>, <span style="color:#000000">HttpServletResponse</span> <span style="color:#000000">response</span>) <span style="color:#770088">throws</span> <span style="color:#000000">IOException</span> {
<span style="color:#000000">BufferedImage</span> <span style="color:#000000">bi</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">BufferedImage</span>(<span style="color:#116644">200</span>, <span style="color:#116644">40</span>, <span style="color:#000000">BufferedImage</span>.<span style="color:#000000">TYPE_INT_RGB</span>);
<span style="color:#000000">Graphics</span> <span style="color:#000000">graphics</span> <span style="color:#981a1a">=</span> <span style="color:#000000">bi</span>.<span style="color:#000000">getGraphics</span>();
<span style="color:#000000">graphics</span>.<span style="color:#000000">setColor</span>(<span style="color:#000000">Color</span>.<span style="color:#000000">GRAY</span>);
<span style="color:#000000">graphics</span>.<span style="color:#000000">fillRect</span>(<span style="color:#116644">0</span>, <span style="color:#116644">0</span>, <span style="color:#116644">200</span>, <span style="color:#116644">40</span>);
<span style="color:#008855">StringBuilder</span> <span style="color:#000000">builder</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#008855">StringBuilder</span>();
<span style="color:#000000">Random</span> <span style="color:#000000">r</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Random</span>();
<span style="color:#770088">for</span>(<span style="color:#008855">int</span> <span style="color:#000000">i</span><span style="color:#981a1a">=</span><span style="color:#116644">0</span>; <span style="color:#000000">i</span><span style="color:#981a1a"><</span><span style="color:#116644">6</span>; <span style="color:#000000">i</span><span style="color:#981a1a">++</span>){
<span style="color:#008855">int</span> <span style="color:#000000">num</span> <span style="color:#981a1a">=</span> <span style="color:#000000">r</span>.<span style="color:#000000">nextInt</span>(<span style="color:#116644">10</span>);
<span style="color:#000000">builder</span>.<span style="color:#000000">append</span>(<span style="color:#000000">num</span>);
<span style="color:#000000">graphics</span>.<span style="color:#000000">setColor</span>(<span style="color:#000000">Color</span>.<span style="color:#000000">red</span>);
<span style="color:#000000">graphics</span>.<span style="color:#000000">drawString</span>(<span style="color:#008855">Integer</span>.<span style="color:#000000">toString</span>(<span style="color:#000000">num</span>), <span style="color:#000000">i</span><span style="color:#981a1a">*</span><span style="color:#116644">10</span> <span style="color:#981a1a">+</span> <span style="color:#116644">20</span>, <span style="color:#116644">15</span>);
}
<span style="color:#aa5500">//创建短信实体</span>
<span style="color:#000000">SmsCode</span> <span style="color:#000000">code</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">SmsCode</span>(<span style="color:#000000">mobile</span>, <span style="color:#000000">builder</span>.<span style="color:#000000">toString</span>(), <span style="color:#000000">System</span>.<span style="color:#000000">currentTimeMillis</span>() <span style="color:#981a1a">+</span> <span style="color:#116644">5</span> <span style="color:#981a1a">*</span> <span style="color:#116644">60</span> <span style="color:#981a1a">*</span> <span style="color:#116644">1000</span>);
<span style="color:#aa5500">//将短信实体放入session中</span>
<span style="color:#000000">session</span>.<span style="color:#000000">setAttribute</span>(<span style="color:#aa1111">"smsCode"</span>, <span style="color:#000000">code</span>);
<span style="color:#000000">graphics</span>.<span style="color:#000000">dispose</span>();
<span style="color:#000000">ImageIO</span>.<span style="color:#000000">write</span>(<span style="color:#000000">bi</span>, <span style="color:#aa1111">"jpg"</span>, <span style="color:#000000">response</span>.<span style="color:#000000">getOutputStream</span>());
}
}</span></span>
2.5 完善短信认证过滤器
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#aa5500">//尝试认证</span>
<span style="color:#555555">@Override</span>
<span style="color:#770088">public</span> <span style="color:#000000">Authentication</span> <span style="color:#0000ff">attemptAuthentication</span>(<span style="color:#000000">HttpServletRequest</span> <span style="color:#000000">request</span>, <span style="color:#000000">HttpServletResponse</span> <span style="color:#000000">response</span>) <span style="color:#770088">throws</span> <span style="color:#000000">AuthenticationException</span>, <span style="color:#000000">IOException</span>, <span style="color:#000000">ServletException</span> {
<span style="color:#770088">if</span>(<span style="color:#981a1a">!</span><span style="color:#000000">request</span>.<span style="color:#000000">getMethod</span>().<span style="color:#000000">equalsIgnoreCase</span>(<span style="color:#aa1111">"POST"</span>)){
<span style="color:#770088">throw</span> <span style="color:#770088">new</span> <span style="color:#000000">AuthenticationServiceException</span>(<span style="color:#aa1111">"Authentication method not supported: "</span> <span style="color:#981a1a">+</span> <span style="color:#000000">request</span>.<span style="color:#000000">getMethod</span>());
}
<span style="color:#008855">String</span> <span style="color:#000000">code</span> <span style="color:#981a1a">=</span> <span style="color:#000000">obtainCode</span>(<span style="color:#000000">request</span>);<span style="color:#aa5500">//获取短信验证码</span>
<span style="color:#aa5500">//从session中获取发送的短信验证码信息</span>
<span style="color:#000000">SmsCode</span> <span style="color:#000000">smsCode</span> <span style="color:#981a1a">=</span> (<span style="color:#000000">SmsCode</span>) <span style="color:#000000">request</span>.<span style="color:#000000">getSession</span>().<span style="color:#000000">getAttribute</span>(<span style="color:#aa1111">"smsCode"</span>);
<span style="color:#770088">if</span>(<span style="color:#000000">code</span> <span style="color:#981a1a">==</span> <span style="color:#221199">null</span> <span style="color:#981a1a">||</span> <span style="color:#000000">smsCode</span> <span style="color:#981a1a">==</span> <span style="color:#221199">null</span>){
<span style="color:#770088">throw</span> <span style="color:#770088">new</span> <span style="color:#000000">AuthenticationServiceException</span>(<span style="color:#aa1111">"SMS code cannot be null"</span>);
}
<span style="color:#008855">String</span> <span style="color:#000000">mobile</span> <span style="color:#981a1a">=</span> <span style="color:#000000">obtainMobile</span>(<span style="color:#000000">request</span>);<span style="color:#aa5500">//获取手机号</span>
<span style="color:#008855">long</span> <span style="color:#000000">currentTime</span> <span style="color:#981a1a">=</span> <span style="color:#000000">System</span>.<span style="color:#000000">currentTimeMillis</span>();<span style="color:#aa5500">//获取系统当前时间</span>
<span style="color:#770088">if</span>(<span style="color:#000000">smsCode</span>.<span style="color:#000000">getExpire</span>() <span style="color:#981a1a"><</span> <span style="color:#000000">currentTime</span> <span style="color:#981a1a">||</span> <span style="color:#981a1a">!</span><span style="color:#000000">mobile</span>.<span style="color:#000000">equals</span>(<span style="color:#000000">smsCode</span>.<span style="color:#000000">getMobile</span>())){<span style="color:#aa5500">//如果系统当前时间比验证码过期时间还要大,说明验证码过期,手机号码与验证码不匹配</span>
<span style="color:#770088">throw</span> <span style="color:#770088">new</span> <span style="color:#000000">AuthenticationServiceException</span>(<span style="color:#aa1111">"SMS code is invalid:"</span> <span style="color:#981a1a">+</span> <span style="color:#000000">smsCode</span>.<span style="color:#000000">getCode</span>());
} <span style="color:#770088">else</span> <span style="color:#770088">if</span>(<span style="color:#981a1a">!</span><span style="color:#000000">code</span>.<span style="color:#000000">equals</span>(<span style="color:#000000">smsCode</span>.<span style="color:#000000">getCode</span>())){
<span style="color:#770088">throw</span> <span style="color:#770088">new</span> <span style="color:#000000">AuthenticationServiceException</span>(<span style="color:#aa1111">"SMS code error"</span>);
}
<span style="color:#000000">SmsAuthenticationToken</span> <span style="color:#000000">token</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">SmsAuthenticationToken</span>(<span style="color:#000000">mobile</span>, <span style="color:#000000">code</span>);<span style="color:#aa5500">//创建SMS token</span>
<span style="color:#770088">this</span>.<span style="color:#000000">setDetails</span>(<span style="color:#000000">request</span>, <span style="color:#000000">token</span>);
<span style="color:#770088">return</span> <span style="color:#770088">this</span>.<span style="color:#000000">getAuthenticationManager</span>().<span style="color:#000000">authenticate</span>(<span style="color:#000000">token</span>);<span style="color:#aa5500">//调用认证管理器认证token</span>
}
<span style="color:#aa5500">//将请求信息放入token中</span>
<span style="color:#770088">protected</span> <span style="color:#008855">void</span> <span style="color:#0000ff">setDetails</span>(<span style="color:#000000">HttpServletRequest</span> <span style="color:#000000">request</span>, <span style="color:#000000">SmsAuthenticationToken</span> <span style="color:#000000">authRequest</span>) {
<span style="color:#000000">authRequest</span>.<span style="color:#000000">setDetails</span>(<span style="color:#770088">this</span>.<span style="color:#000000">authenticationDetailsSource</span>.<span style="color:#000000">buildDetails</span>(<span style="color:#000000">request</span>));
}</span></span>
2.6 创建短信认证提供器
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">qf</span>.<span style="color:#000000">authentication</span>.<span style="color:#000000">sms</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">authentication</span>.<span style="color:#000000">AuthenticationProvider</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">core</span>.<span style="color:#000000">Authentication</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">core</span>.<span style="color:#000000">AuthenticationException</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">core</span>.<span style="color:#000000">userdetails</span>.<span style="color:#000000">UserDetails</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">core</span>.<span style="color:#000000">userdetails</span>.<span style="color:#000000">UserDetailsService</span>;
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">SmsAuthenticationProvider</span> <span style="color:#770088">implements</span> <span style="color:#000000">AuthenticationProvider</span> {
<span style="color:#aa5500">//获取认证用户的信息的服务接口</span>
<span style="color:#770088">private</span> <span style="color:#000000">UserDetailsService</span> <span style="color:#000000">userDetailsService</span>;
<span style="color:#aa5500">/**</span>
<span style="color:#aa5500">* 这个方法就是认证,如果没有抛出认证异常,说明认证成功</span>
<span style="color:#aa5500">* @param authentication 未进行认证的信息,里面就是包含了一个mobile信息和请求的信息</span>
<span style="color:#aa5500">* @return 返回一个认证完成的信息</span>
<span style="color:#aa5500">* @throws AuthenticationException</span>
<span style="color:#aa5500">*/</span>
<span style="color:#555555">@Override</span>
<span style="color:#770088">public</span> <span style="color:#000000">Authentication</span> <span style="color:#000000">authenticate</span>(<span style="color:#000000">Authentication</span> <span style="color:#000000">authentication</span>) <span style="color:#770088">throws</span> <span style="color:#000000">AuthenticationException</span> {
<span style="color:#008855">String</span> <span style="color:#000000">mobile</span> <span style="color:#981a1a">=</span> (<span style="color:#008855">String</span>) <span style="color:#000000">authentication</span>.<span style="color:#000000">getPrincipal</span>();
<span style="color:#000000">UserDetails</span> <span style="color:#000000">userDetails</span> <span style="color:#981a1a">=</span> <span style="color:#000000">userDetailsService</span>.<span style="color:#000000">loadUserByUsername</span>(<span style="color:#000000">mobile</span>); <span style="color:#aa5500">//通过手机号码获取用户信息</span>
<span style="color:#000000">SmsAuthenticationToken</span> <span style="color:#000000">authenticationToken</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">SmsAuthenticationToken</span>(<span style="color:#000000">userDetails</span>, <span style="color:#000000">authentication</span>.<span style="color:#000000">getCredentials</span>(), <span style="color:#000000">userDetails</span>.<span style="color:#000000">getAuthorities</span>());
<span style="color:#000000">authenticationToken</span>.<span style="color:#000000">setDetails</span>(<span style="color:#000000">authentication</span>.<span style="color:#000000">getDetails</span>());
<span style="color:#770088">return</span> <span style="color:#000000">authenticationToken</span>;
}
<span style="color:#555555">@Override</span>
<span style="color:#770088">public</span> <span style="color:#008855">boolean</span> <span style="color:#000000">supports</span>(<span style="color:#000000">Class</span><span style="color:#981a1a"><?></span> <span style="color:#000000">authentication</span>) {
<span style="color:#aa5500">// 判断 authentication 是不是 SmsCodeAuthenticationToken 类型或者其子类或者其子接口</span>
<span style="color:#770088">return</span> <span style="color:#000000">SmsAuthenticationToken</span>.<span style="color:#770088">class</span>.<span style="color:#000000">isAssignableFrom</span>(<span style="color:#000000">authentication</span>);
}
<span style="color:#770088">public</span> <span style="color:#000000">UserDetailsService</span> <span style="color:#000000">getUserDetailsService</span>() {
<span style="color:#770088">return</span> <span style="color:#000000">userDetailsService</span>;
}
<span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">setUserDetailsService</span>(<span style="color:#000000">UserDetailsService</span> <span style="color:#000000">userDetailsService</span>) {
<span style="color:#770088">this</span>.<span style="color:#000000">userDetailsService</span> <span style="color:#981a1a">=</span> <span style="color:#000000">userDetailsService</span>;
}
}</span></span>
2.7 配置短信认证
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">qf</span>.<span style="color:#000000">authentication</span>.<span style="color:#000000">config</span>;
<span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">qf</span>.<span style="color:#000000">authentication</span>.<span style="color:#000000">handler</span>.<span style="color:#000000">LoginFailureHandler</span>;
<span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">qf</span>.<span style="color:#000000">authentication</span>.<span style="color:#000000">handler</span>.<span style="color:#000000">LoginSuccessHandler</span>;
<span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">qf</span>.<span style="color:#000000">authentication</span>.<span style="color:#000000">service</span>.<span style="color:#000000">UserService</span>;
<span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">qf</span>.<span style="color:#000000">authentication</span>.<span style="color:#000000">sms</span>.<span style="color:#000000">SmsAuthenticationFilter</span>;
<span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">qf</span>.<span style="color:#000000">authentication</span>.<span style="color:#000000">sms</span>.<span style="color:#000000">SmsAuthenticationProvider</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">beans</span>.<span style="color:#000000">factory</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">Autowired</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">beans</span>.<span style="color:#000000">factory</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">Qualifier</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">context</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">Bean</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">http</span>.<span style="color:#000000">HttpMethod</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">authentication</span>.<span style="color:#000000">AuthenticationManager</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">authentication</span>.<span style="color:#000000">dao</span>.<span style="color:#000000">DaoAuthenticationProvider</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">config</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">authentication</span>.<span style="color:#000000">builders</span>.<span style="color:#000000">AuthenticationManagerBuilder</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">config</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">web</span>.<span style="color:#000000">builders</span>.<span style="color:#000000">HttpSecurity</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">config</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">web</span>.<span style="color:#000000">configuration</span>.<span style="color:#000000">EnableWebSecurity</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">config</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">web</span>.<span style="color:#000000">configuration</span>.<span style="color:#000000">WebSecurityConfigurerAdapter</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">crypto</span>.<span style="color:#000000">bcrypt</span>.<span style="color:#000000">BCryptPasswordEncoder</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">crypto</span>.<span style="color:#000000">password</span>.<span style="color:#000000">PasswordEncoder</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">web</span>.<span style="color:#000000">authentication</span>.<span style="color:#000000">UsernamePasswordAuthenticationFilter</span>;
<span style="color:#555555">@EnableWebSecurity</span> <span style="color:#aa5500">//启用security</span>
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">SecurityConfig</span> <span style="color:#770088">extends</span> <span style="color:#000000">WebSecurityConfigurerAdapter</span> {
<span style="color:#555555">@Autowired</span>
<span style="color:#770088">private</span> <span style="color:#000000">UserService</span> <span style="color:#000000">userService</span>;
<span style="color:#555555">@Autowired</span>
<span style="color:#770088">private</span> <span style="color:#000000">LoginSuccessHandler</span> <span style="color:#000000">loginSuccessHandler</span>;
<span style="color:#555555">@Autowired</span>
<span style="color:#770088">private</span> <span style="color:#000000">LoginFailureHandler</span> <span style="color:#000000">loginFailureHandler</span>;
<span style="color:#555555">@Autowired</span>
<span style="color:#555555">@Qualifier</span>(<span style="color:#aa1111">"authenticationManagerBean"</span>) <span style="color:#aa5500">//表示使用指定名称的认证管理器</span>
<span style="color:#770088">private</span> <span style="color:#000000">AuthenticationManager</span> <span style="color:#000000">authenticationManager</span>;
<span style="color:#aa5500">//创建密码加密器,并纳入Spring IOC容器管理,该Bean的名字就是方法名</span>
<span style="color:#555555">@Bean</span>
<span style="color:#770088">public</span> <span style="color:#000000">PasswordEncoder</span> <span style="color:#000000">passwordEncoder</span>(){
<span style="color:#770088">return</span> <span style="color:#770088">new</span> <span style="color:#000000">BCryptPasswordEncoder</span>();
}
<span style="color:#aa5500">//认证管理器配置</span>
<span style="color:#555555">@Override</span>
<span style="color:#770088">protected</span> <span style="color:#008855">void</span> <span style="color:#000000">configure</span>(<span style="color:#000000">AuthenticationManagerBuilder</span> <span style="color:#000000">auth</span>) <span style="color:#770088">throws</span> <span style="color:#000000">Exception</span> {
<span style="color:#aa5500">//创建短信认证提供器</span>
<span style="color:#000000">SmsAuthenticationProvider</span> <span style="color:#000000">smsAuthenticationProvider</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">SmsAuthenticationProvider</span>();
<span style="color:#000000">smsAuthenticationProvider</span>.<span style="color:#000000">setUserDetailsService</span>(<span style="color:#000000">userService</span>);
<span style="color:#aa5500">//将认证提供器添加到认证管理器中</span>
<span style="color:#000000">auth</span>.<span style="color:#000000">authenticationProvider</span>(<span style="color:#000000">smsAuthenticationProvider</span>);
<span style="color:#aa5500">//数据库数据认证提供器</span>
<span style="color:#000000">DaoAuthenticationProvider</span> <span style="color:#000000">daoAuthenticationProvider</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">DaoAuthenticationProvider</span>();
<span style="color:#aa5500">//设置认证使用的用户详情服务,业就是查询用户信息的服务</span>
<span style="color:#000000">daoAuthenticationProvider</span>.<span style="color:#000000">setUserDetailsService</span>(<span style="color:#000000">userService</span>);
<span style="color:#aa5500">//设置密码使用的加密器</span>
<span style="color:#000000">daoAuthenticationProvider</span>.<span style="color:#000000">setPasswordEncoder</span>(<span style="color:#000000">passwordEncoder</span>());
<span style="color:#aa5500">//设置认证管理构建器使用的认证提供器</span>
<span style="color:#000000">auth</span>.<span style="color:#000000">authenticationProvider</span>(<span style="color:#000000">daoAuthenticationProvider</span>);
}
<span style="color:#aa5500">//Http认证配置</span>
<span style="color:#555555">@Override</span>
<span style="color:#770088">protected</span> <span style="color:#008855">void</span> <span style="color:#000000">configure</span>(<span style="color:#000000">HttpSecurity</span> <span style="color:#000000">http</span>) <span style="color:#770088">throws</span> <span style="color:#000000">Exception</span> {
<span style="color:#000000">http</span>.<span style="color:#000000">csrf</span>().<span style="color:#000000">disable</span>();<span style="color:#aa5500">//关闭跨站请求模拟</span>
<span style="color:#aa5500">//设置表单登录使用的登录地址、登录请求的URL地址、登录成功和失败分别使用的处理器 permitAll表示该操作不需要security的权限控制</span>
<span style="color:#000000">http</span>.<span style="color:#000000">formLogin</span>().<span style="color:#000000">loginPage</span>(<span style="color:#aa1111">"/"</span>).<span style="color:#000000">loginProcessingUrl</span>(<span style="color:#aa1111">"/login"</span>)
.<span style="color:#000000">successHandler</span>(<span style="color:#000000">loginSuccessHandler</span>).<span style="color:#000000">failureHandler</span>(<span style="color:#000000">loginFailureHandler</span>).<span style="color:#000000">permitAll</span>();
<span style="color:#aa5500">//设置获取验证码的请求放行</span>
<span style="color:#000000">http</span>.<span style="color:#000000">authorizeRequests</span>().<span style="color:#000000">antMatchers</span>(<span style="color:#000000">HttpMethod</span>.<span style="color:#000000">GET</span>, <span style="color:#aa1111">"/code"</span>).<span style="color:#000000">permitAll</span>()
<span style="color:#aa5500">//其他请求需要认证</span>
.<span style="color:#000000">anyRequest</span>().<span style="color:#000000">authenticated</span>();
<span style="color:#aa5500">//设置退出操作使当前session失效 permitAll表示该操作不需要security的权限控制</span>
<span style="color:#000000">http</span>.<span style="color:#000000">logout</span>().<span style="color:#000000">invalidateHttpSession</span>(<span style="color:#221199">true</span>).<span style="color:#000000">permitAll</span>();
<span style="color:#aa5500">//将短信认证过滤器添加账号密码过滤器的前面</span>
<span style="color:#000000">http</span>.<span style="color:#000000">addFilterBefore</span>(<span style="color:#000000">smsAuthenticationFilter</span>(), <span style="color:#000000">UsernamePasswordAuthenticationFilter</span>.<span style="color:#770088">class</span>);
}
<span style="color:#555555">@Bean</span>
<span style="color:#555555">@Override</span>
<span style="color:#770088">public</span> <span style="color:#000000">AuthenticationManager</span> <span style="color:#000000">authenticationManagerBean</span>() <span style="color:#770088">throws</span> <span style="color:#000000">Exception</span> {
<span style="color:#770088">return</span> <span style="color:#770088">super</span>.<span style="color:#000000">authenticationManagerBean</span>();
}
<span style="color:#555555">@Bean</span>
<span style="color:#770088">public</span> <span style="color:#000000">SmsAuthenticationFilter</span> <span style="color:#000000">smsAuthenticationFilter</span>() <span style="color:#770088">throws</span> <span style="color:#000000">Exception</span> {
<span style="color:#000000">SmsAuthenticationFilter</span> <span style="color:#000000">smsAuthenticationFilter</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">SmsAuthenticationFilter</span>();
<span style="color:#aa5500">//设置短信认证过滤器使用的认证管理器</span>
<span style="color:#000000">smsAuthenticationFilter</span>.<span style="color:#000000">setAuthenticationManager</span>(<span style="color:#000000">authenticationManager</span>);
<span style="color:#aa5500">//设置登录成功的处理器</span>
<span style="color:#000000">smsAuthenticationFilter</span>.<span style="color:#000000">setAuthenticationSuccessHandler</span>(<span style="color:#000000">loginSuccessHandler</span>);
<span style="color:#aa5500">//设置登录失败的处理器</span>
<span style="color:#000000">smsAuthenticationFilter</span>.<span style="color:#000000">setAuthenticationFailureHandler</span>(<span style="color:#000000">loginFailureHandler</span>);
<span style="color:#770088">return</span> <span style="color:#000000">smsAuthenticationFilter</span>;
}
}</span></span>
2.8 修改登录页面
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#555555"><!DOCTYPE html></span>
<span style="color:#117700"><</span><span style="color:#117700">html</span> <span style="color:#0000cc">lang</span>=<span style="color:#aa1111">"en"</span><span style="color:#117700">></span>
<span style="color:#117700"><</span><span style="color:#117700">head</span><span style="color:#117700">></span>
<span style="color:#117700"><</span><span style="color:#117700">meta</span> <span style="color:#0000cc">charset</span>=<span style="color:#aa1111">"UTF-8"</span><span style="color:#117700">></span>
<span style="color:#117700"><</span><span style="color:#117700">title</span><span style="color:#117700">></span>Security登录<span style="color:#117700"></</span><span style="color:#117700">title</span><span style="color:#117700">></span>
<span style="color:#117700"></</span><span style="color:#117700">head</span><span style="color:#117700">></span>
<span style="color:#117700"><</span><span style="color:#117700">body</span><span style="color:#117700">></span>
<span style="color:#117700"><</span><span style="color:#117700">form</span> <span style="color:#0000cc">action</span>=<span style="color:#aa1111">"login"</span> <span style="color:#0000cc">method</span>=<span style="color:#aa1111">"post"</span><span style="color:#117700">></span>
<span style="color:#117700"><</span><span style="color:#117700">input</span> <span style="color:#0000cc">type</span>=<span style="color:#aa1111">"text"</span> <span style="color:#0000cc">name</span>=<span style="color:#aa1111">"username"</span><span style="color:#117700">></span>
<span style="color:#117700"><</span><span style="color:#117700">input</span> <span style="color:#0000cc">type</span>=<span style="color:#aa1111">"password"</span> <span style="color:#0000cc">name</span>=<span style="color:#aa1111">"password"</span><span style="color:#117700">></span>
<span style="color:#117700"><</span><span style="color:#117700">input</span> <span style="color:#0000cc">type</span>=<span style="color:#aa1111">"submit"</span> <span style="color:#0000cc">value</span>=<span style="color:#aa1111">"登录"</span><span style="color:#117700">></span>
<span style="color:#117700"></</span><span style="color:#117700">form</span><span style="color:#117700">></span>
<span style="color:#117700"><</span><span style="color:#117700">form</span> <span style="color:#0000cc">action</span>=<span style="color:#aa1111">"sms"</span> <span style="color:#0000cc">method</span>=<span style="color:#aa1111">"post"</span> <span style="color:#117700">></span>
<span style="color:#117700"><</span><span style="color:#117700">input</span> <span style="color:#0000cc">type</span>=<span style="color:#aa1111">"text"</span> <span style="color:#0000cc">name</span>=<span style="color:#aa1111">"mobile"</span><span style="color:#117700">></span>
<span style="color:#117700"><</span><span style="color:#117700">input</span> <span style="color:#0000cc">type</span>=<span style="color:#aa1111">"text"</span> <span style="color:#0000cc">name</span>=<span style="color:#aa1111">"code"</span><span style="color:#117700">></span>
<span style="color:#117700"><</span><span style="color:#117700">input</span> <span style="color:#0000cc">type</span>=<span style="color:#aa1111">"button"</span> <span style="color:#0000cc">value</span>=<span style="color:#aa1111">"获取验证码"</span> <span style="color:#0000cc">onclick</span>=<span style="color:#aa1111">"getCode()"</span><span style="color:#117700">></span>
<span style="color:#117700"><</span><span style="color:#117700">input</span> <span style="color:#0000cc">type</span>=<span style="color:#aa1111">"submit"</span> <span style="color:#0000cc">value</span>=<span style="color:#aa1111">"登录"</span><span style="color:#117700">></span>
<span style="color:#117700"></</span><span style="color:#117700">form</span><span style="color:#117700">></span>
<span style="color:#117700"></</span><span style="color:#117700">body</span><span style="color:#117700">></span>
<span style="color:#117700"><</span><span style="color:#117700">script</span> <span style="color:#0000cc">type</span>=<span style="color:#aa1111">"text/javascript"</span><span style="color:#117700">></span>
<span style="color:#770088">function</span> <span style="color:#0000ff">getCode</span>(){
<span style="color:#770088">let</span> <span style="color:#0000ff">elements</span> <span style="color:#981a1a">=</span> <span style="color:#000000">document</span>.<span style="color:#000000">getElementsByName</span>(<span style="color:#aa1111">"code"</span>);
<span style="color:#770088">let</span> <span style="color:#0000ff">img</span> <span style="color:#981a1a">=</span> <span style="color:#000000">document</span>.<span style="color:#000000">createElement</span>(<span style="color:#aa1111">"img"</span>);
<span style="color:#0055aa">img</span>.<span style="color:#000000">src</span> <span style="color:#981a1a">=</span> <span style="color:#aa1111">"code?mobile="</span> <span style="color:#981a1a">+</span> <span style="color:#000000">document</span>.<span style="color:#000000">getElementsByName</span>(<span style="color:#aa1111">"mobile"</span>)[<span style="color:#116644">0</span>].<span style="color:#000000">value</span>;
<span style="color:#0055aa">elements</span>[<span style="color:#116644">0</span>].<span style="color:#000000">after</span>(<span style="color:#0055aa">img</span>);
}
<span style="color:#117700"></</span><span style="color:#117700">script</span><span style="color:#117700">></span>
<span style="color:#117700"></</span><span style="color:#117700">html</span><span style="color:#117700">></span></span></span>
第四节 Spring Security 授权
1. 启用注解授权
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#555555">@EnableWebSecurity</span> <span style="color:#aa5500">//启用security</span>
<span style="color:#aa5500">//prePostEnabled = true启用@PreAuthorize()</span>
<span style="color:#aa5500">//securedEnabled = true启用@Secured()</span>
<span style="color:#aa5500">//jsr250Enabled = true启用@RolesAllowed、@PermitAll、@DenyAll 但该注解需要jar包支撑</span>
<span style="color:#555555">@EnableGlobalMethodSecurity</span>(<span style="color:#000000">prePostEnabled</span> <span style="color:#981a1a">=</span> <span style="color:#221199">true</span>, <span style="color:#000000">securedEnabled</span> <span style="color:#981a1a">=</span> <span style="color:#221199">true</span>, <span style="color:#000000">jsr250Enabled</span> <span style="color:#981a1a">=</span> <span style="color:#221199">true</span>)
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">SecurityConfig</span> <span style="color:#770088">extends</span> <span style="color:#000000">WebSecurityConfigurerAdapter</span> {}</span></span>
JSR 250 依赖包
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#aa5500"><!--jsr250--></span>
<span style="color:#117700"><</span><span style="color:#117700">dependency</span><span style="color:#117700">></span>
<span style="color:#117700"><</span><span style="color:#117700">groupId</span><span style="color:#117700">></span>javax.annotation<span style="color:#117700"></</span><span style="color:#117700">groupId</span><span style="color:#117700">></span>
<span style="color:#117700"><</span><span style="color:#117700">artifactId</span><span style="color:#117700">></span>jsr250-api<span style="color:#117700"></</span><span style="color:#117700">artifactId</span><span style="color:#117700">></span>
<span style="color:#117700"><</span><span style="color:#117700">version</span><span style="color:#117700">></span>1.0<span style="color:#117700"></</span><span style="color:#117700">version</span><span style="color:#117700">></span>
<span style="color:#117700"></</span><span style="color:#117700">dependency</span><span style="color:#117700">></span></span></span>
2. HTTP授权配置
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#aa5500">//Http认证配置</span>
<span style="color:#555555">@Override</span>
<span style="color:#770088">protected</span> <span style="color:#008855">void</span> <span style="color:#0000ff">configure</span>(<span style="color:#000000">HttpSecurity</span> <span style="color:#000000">http</span>) <span style="color:#770088">throws</span> <span style="color:#000000">Exception</span> {
<span style="color:#000000">http</span>.<span style="color:#000000">csrf</span>().<span style="color:#000000">disable</span>();<span style="color:#aa5500">//关闭跨站请求模拟</span>
<span style="color:#aa5500">//设置表单登录使用的登录地址、登录请求的URL地址、登录成功和失败分别使用的处理器 permitAll表示该操作不需要security的权限控制</span>
<span style="color:#000000">http</span>.<span style="color:#000000">formLogin</span>().<span style="color:#000000">loginPage</span>(<span style="color:#aa1111">"/"</span>).<span style="color:#000000">loginProcessingUrl</span>(<span style="color:#aa1111">"/login"</span>)
.<span style="color:#000000">successHandler</span>(<span style="color:#000000">loginSuccessHandler</span>).<span style="color:#000000">failureHandler</span>(<span style="color:#000000">loginFailureHandler</span>).<span style="color:#000000">permitAll</span>();
<span style="color:#aa5500">//设置获取验证码的请求放行</span>
<span style="color:#000000">http</span>.<span style="color:#000000">authorizeRequests</span>().<span style="color:#000000">antMatchers</span>(<span style="color:#000000">HttpMethod</span>.<span style="color:#000000">GET</span>, <span style="color:#aa1111">"/code"</span>).<span style="color:#000000">permitAll</span>()
<span style="color:#aa5500">//授权请求表示任意请求都需要认证才能够访问</span>
.<span style="color:#000000">anyRequest</span>().<span style="color:#000000">authenticated</span>();
<span style="color:#aa5500">//设置异常处理使用访问拒绝处理器</span>
<span style="color:#000000">http</span>.<span style="color:#000000">exceptionHandling</span>().<span style="color:#000000">accessDeniedHandler</span>();
<span style="color:#aa5500">//设置退出操作使当前session失效 permitAll表示该操作不需要security的权限控制</span>
<span style="color:#000000">http</span>.<span style="color:#000000">logout</span>().<span style="color:#000000">invalidateHttpSession</span>(<span style="color:#221199">true</span>).<span style="color:#000000">permitAll</span>();
<span style="color:#aa5500">//将短信认证过滤器添加账号密码过滤器的前面</span>
<span style="color:#000000">http</span>.<span style="color:#000000">addFilterBefore</span>(<span style="color:#000000">smsAuthenticationFilter</span>(), <span style="color:#000000">UsernamePasswordAuthenticationFilter</span>.<span style="color:#770088">class</span>);
}</span></span>
3. 创建拒绝请求处理器
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">qf</span>.<span style="color:#000000">authentication</span>.<span style="color:#000000">handler</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">access</span>.<span style="color:#000000">AccessDeniedException</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">web</span>.<span style="color:#000000">access</span>.<span style="color:#000000">AccessDeniedHandler</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">stereotype</span>.<span style="color:#000000">Component</span>;
<span style="color:#770088">import</span> <span style="color:#000000">javax</span>.<span style="color:#000000">servlet</span>.<span style="color:#000000">ServletException</span>;
<span style="color:#770088">import</span> <span style="color:#000000">javax</span>.<span style="color:#000000">servlet</span>.<span style="color:#000000">http</span>.<span style="color:#000000">HttpServletRequest</span>;
<span style="color:#770088">import</span> <span style="color:#000000">javax</span>.<span style="color:#000000">servlet</span>.<span style="color:#000000">http</span>.<span style="color:#000000">HttpServletResponse</span>;
<span style="color:#770088">import</span> <span style="color:#000000">java</span>.<span style="color:#000000">io</span>.<span style="color:#000000">IOException</span>;
<span style="color:#aa5500">//HTTP请求被拒绝的处理器</span>
<span style="color:#555555">@Component</span>
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">RequestDeniedHandler</span> <span style="color:#770088">implements</span> <span style="color:#000000">AccessDeniedHandler</span> {
<span style="color:#aa5500">//这里就是拒绝处理的具体步骤实现</span>
<span style="color:#555555">@Override</span>
<span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">handle</span>(<span style="color:#000000">HttpServletRequest</span> <span style="color:#000000">request</span>, <span style="color:#000000">HttpServletResponse</span> <span style="color:#000000">response</span>, <span style="color:#000000">AccessDeniedException</span> <span style="color:#000000">accessDeniedException</span>) <span style="color:#770088">throws</span> <span style="color:#000000">IOException</span>, <span style="color:#000000">ServletException</span> {
<span style="color:#000000">response</span>.<span style="color:#000000">setContentType</span>(<span style="color:#aa1111">"text/html;charset=utf-8"</span>);
<span style="color:#aa5500">//返回拒绝处理的信息</span>
<span style="color:#000000">response</span>.<span style="color:#000000">getWriter</span>().<span style="color:#000000">print</span>(<span style="color:#000000">accessDeniedException</span>.<span style="color:#000000">getMessage</span>());
}
}</span></span>
5. 完善HTTP授权配置
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#555555">@Autowired</span>
<span style="color:#770088">private</span> <span style="color:#000000">RequestDecisionManager</span> <span style="color:#000000">decisionManager</span>;
<span style="color:#555555">@Autowired</span>
<span style="color:#770088">private</span> <span style="color:#000000">RequestDeniedHandler</span> <span style="color:#000000">deniedHandler</span>;
<span style="color:#aa5500">//Http认证配置</span>
<span style="color:#555555">@Override</span>
<span style="color:#770088">protected</span> <span style="color:#008855">void</span> <span style="color:#0000ff">configure</span>(<span style="color:#000000">HttpSecurity</span> <span style="color:#000000">http</span>) <span style="color:#770088">throws</span> <span style="color:#000000">Exception</span> {
<span style="color:#000000">http</span>.<span style="color:#000000">csrf</span>().<span style="color:#000000">disable</span>();<span style="color:#aa5500">//关闭跨站请求模拟</span>
<span style="color:#aa5500">//设置表单登录使用的登录地址、登录请求的URL地址、登录成功和失败分别使用的处理器 permitAll表示该操作不需要security的权限控制</span>
<span style="color:#000000">http</span>.<span style="color:#000000">formLogin</span>().<span style="color:#000000">loginPage</span>(<span style="color:#aa1111">"/"</span>).<span style="color:#000000">loginProcessingUrl</span>(<span style="color:#aa1111">"/login"</span>)
.<span style="color:#000000">successHandler</span>(<span style="color:#000000">loginSuccessHandler</span>).<span style="color:#000000">failureHandler</span>(<span style="color:#000000">loginFailureHandler</span>).<span style="color:#000000">permitAll</span>();
<span style="color:#aa5500">//设置获取验证码的请求放行</span>
<span style="color:#000000">http</span>.<span style="color:#000000">authorizeRequests</span>().<span style="color:#000000">antMatchers</span>(<span style="color:#000000">HttpMethod</span>.<span style="color:#000000">GET</span>, <span style="color:#aa1111">"/code"</span>).<span style="color:#000000">permitAll</span>()
<span style="color:#aa5500">//授权请求表示任意请求都需要认证才能够访问</span>
.<span style="color:#000000">anyRequest</span>().<span style="color:#000000">authenticated</span>();
<span style="color:#aa5500">//设置异常处理使用访问拒绝处理器</span>
<span style="color:#000000">http</span>.<span style="color:#000000">exceptionHandling</span>().<span style="color:#000000">accessDeniedHandler</span>(<span style="color:#000000">deniedHandler</span>);
<span style="color:#aa5500">//设置退出操作使当前session失效 permitAll表示该操作不需要security的权限控制</span>
<span style="color:#000000">http</span>.<span style="color:#000000">logout</span>().<span style="color:#000000">invalidateHttpSession</span>(<span style="color:#221199">true</span>).<span style="color:#000000">permitAll</span>();
<span style="color:#aa5500">//将短信认证过滤器添加账号密码过滤器的前面</span>
<span style="color:#000000">http</span>.<span style="color:#000000">addFilterBefore</span>(<span style="color:#000000">smsAuthenticationFilter</span>(), <span style="color:#000000">UsernamePasswordAuthenticationFilter</span>.<span style="color:#770088">class</span>);
}</span></span>
6. 创建测试请求
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">qf</span>.<span style="color:#000000">authentication</span>.<span style="color:#000000">controller</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">access</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">Secured</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">security</span>.<span style="color:#000000">access</span>.<span style="color:#000000">prepost</span>.<span style="color:#000000">PreAuthorize</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">web</span>.<span style="color:#000000">bind</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">GetMapping</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">web</span>.<span style="color:#000000">bind</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">RestController</span>;
<span style="color:#770088">import</span> <span style="color:#000000">javax</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">security</span>.<span style="color:#000000">RolesAllowed</span>;
<span style="color:#555555">@RestController</span>
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">TestController</span> {
<span style="color:#555555">@GetMapping</span>(<span style="color:#aa1111">"/test1"</span>)
<span style="color:#555555">@PreAuthorize</span>(<span style="color:#aa1111">"hasRole('ROLE_ADMIN')"</span>)
<span style="color:#770088">public</span> <span style="color:#008855">String</span> <span style="color:#000000">test1</span>(){
<span style="color:#770088">return</span> <span style="color:#aa1111">"test1"</span>;
}
<span style="color:#555555">@GetMapping</span>(<span style="color:#aa1111">"/test2"</span>)
<span style="color:#555555">@PreAuthorize</span>(<span style="color:#aa1111">"hasRole('ROLE_TEST')"</span>)
<span style="color:#770088">public</span> <span style="color:#008855">String</span> <span style="color:#000000">test2</span>(){
<span style="color:#770088">return</span> <span style="color:#aa1111">"test2"</span>;
}
<span style="color:#555555">@GetMapping</span>(<span style="color:#aa1111">"/test3"</span>)
<span style="color:#555555">@Secured</span>(<span style="color:#aa1111">"ROLE_ADMIN"</span>)
<span style="color:#770088">public</span> <span style="color:#008855">String</span> <span style="color:#000000">test3</span>(){
<span style="color:#770088">return</span> <span style="color:#aa1111">"test3"</span>;
}
<span style="color:#555555">@GetMapping</span>(<span style="color:#aa1111">"/test4"</span>)
<span style="color:#555555">@Secured</span>(<span style="color:#aa1111">"ROLE_TEST"</span>)
<span style="color:#770088">public</span> <span style="color:#008855">String</span> <span style="color:#000000">test4</span>(){
<span style="color:#770088">return</span> <span style="color:#aa1111">"test4"</span>;
}
<span style="color:#555555">@GetMapping</span>(<span style="color:#aa1111">"/test5"</span>)
<span style="color:#555555">@RolesAllowed</span>(<span style="color:#aa1111">"ROLE_ADMIN"</span>)
<span style="color:#770088">public</span> <span style="color:#008855">String</span> <span style="color:#000000">test5</span>(){
<span style="color:#770088">return</span> <span style="color:#aa1111">"test5"</span>;
}
<span style="color:#555555">@GetMapping</span>(<span style="color:#aa1111">"/test6"</span>)
<span style="color:#555555">@RolesAllowed</span>(<span style="color:#aa1111">"ROLE_TEST"</span>)
<span style="color:#770088">public</span> <span style="color:#008855">String</span> <span style="color:#000000">test6</span>(){
<span style="color:#770088">return</span> <span style="color:#aa1111">"test6"</span>;
}
}</span></span>
7. 启动程序进行测试
第五节 Security 与 AJAX 对接
这个问题的根本原因在于登录结果的处理和拒绝访问的处理。如果能够判断一个请求是ajax请求,那么问题即将得到解决。
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">qf</span>.<span style="color:#000000">security</span>.<span style="color:#000000">util</span>;
<span style="color:#770088">import</span> <span style="color:#000000">javax</span>.<span style="color:#000000">servlet</span>.<span style="color:#000000">http</span>.<span style="color:#000000">HttpServletRequest</span>;
<span style="color:#aa5500">/**</span>
<span style="color:#aa5500">* @Author: wu</span>
<span style="color:#aa5500">* @Description:</span>
<span style="color:#aa5500">* @Date: 2021-11-09</span>
<span style="color:#aa5500">*/</span>
<span style="color:#aa5500">//针对请求相关的操作工具类</span>
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">RequestUtil</span> {
<span style="color:#770088">private</span> <span style="color:#000000">RequestUtil</span>(){}
<span style="color:#aa5500">/**</span>
<span style="color:#aa5500">* 验证请求是否是AJAX请求 这种验证对于jQuery发送的AJAX没有任何问题</span>
<span style="color:#aa5500">* 但是,对于 axios发送的AJAX可能存在没有X-Requested-With这个头信</span>
<span style="color:#aa5500">* 息的</span>
<span style="color:#aa5500">* @param request</span>
<span style="color:#aa5500">* @return</span>
<span style="color:#aa5500">*/</span>
<span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">boolean</span> <span style="color:#000000">isAjaxRequest</span>(<span style="color:#000000">HttpServletRequest</span> <span style="color:#000000">request</span>){
<span style="color:#008855">String</span> <span style="color:#000000">header</span> <span style="color:#981a1a">=</span> <span style="color:#000000">request</span>.<span style="color:#000000">getHeader</span>(<span style="color:#aa1111">"X-Requested-With"</span>);
<span style="color:#770088">return</span> <span style="color:#aa1111">"XMLHttpRequest"</span>.<span style="color:#000000">equalsIgnoreCase</span>(<span style="color:#000000">header</span>);
}
}</span></span>
登录的时候传递的参数在过滤器中获取不到,需要注意:在传递参数的时候要使用get方法传递参数的方式对参数进行拼接,然后赋值给data
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#000000">$</span>.<span style="color:#000000">ajax</span>({
<span style="color:#000000">type</span>: <span style="color:#aa1111">'post'</span>,
<span style="color:#000000">url</span>: <span style="color:#aa1111">'login'</span>,
<span style="color:#000000">data</span>: <span style="color:#aa1111">"username="</span><span style="color:#981a1a">+</span> <span style="color:#000000">$</span>(<span style="color:#aa1111">"#username"</span>).<span style="color:#000000">val</span>() <span style="color:#981a1a">+</span> <span style="color:#aa1111">"&password="</span> <span style="color:#981a1a">+</span> <span style="color:#000000">$</span>(<span style="color:#aa1111">"#password"</span>).<span style="color:#000000">val</span>(),
<span style="color:#000000">success</span>: <span style="color:#770088">function</span> (<span style="color:#0000ff">resp</span>) {
<span style="color:#000000">console</span>.<span style="color:#000000">log</span>(<span style="color:#0055aa">resp</span>);
}
});</span></span>
原文地址:https://blog.csdn.net/JAVA_KX/article/details/130691948
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_42560.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!