1.初次使用
| 模块名称 | default-demo | 
|---|---|
| 功能描述 | 完成登录后,才能对接口进行访问 | 
1.1依赖导入
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--security--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency>
1.2配置类
@EnableWebSecuritypublic class SecurityConfig extends WebSecurityConfigurerAdapter {}
1.3Controller接口
@RestControllerpublic class DefaultDemoController {@GetMapping("query")public String query(){return "stu list";}}
1.4启动后控制台
1.5通过浏览器访问 query 接口
①浏览器输入:localhost:8080/query
②页面会自动跳转到:一个登录页(localhost:8080/login)
③输入用户名:user,用户密码:f30bcf90-bd54-4ae0-a934-5dc66ba8dd34(控制台打印出来的)进行登录,即可完成登录,并自动跳转到 query接口
1.6框架做了什么?
①用户输入localhost:8080/query
②此接口请求被springSecurity框架中的过滤器拦截,并重定向页面到一个(localhost:8080/login)上。
③用户输入了用户名和密码
④SpringSecurity框架中的代码进行用户名密码的校验。
⑤校验失败,返回登录失败
⑥校验成功,跳转到之前访问的 query接口上
1.7以上流程中需要自定义东西
①当用户未登录时,我希望跳转到我指定的登录页面。
②用户的校验逻辑需要我自己去定义(查询数据库校验)
2.自定义登录页面
2.1定义一个登录页面
2.2修改配置类
@EnableWebSecuritypublic class SecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate MyLoginFailureHandler myLoginFailureHandler;@Overrideprotected void configure(HttpSecurity http) throws Exception {//页面名称必须加 /http.formLogin().loginPage("/mylogin.html").and().authorizeRequests().antMatchers("/mylogin.html").permitAll().and().authorizeRequests().anyRequest().authenticated(); //所有的请求都需要认证后访问}}
2.3访问query接口
2.4进行登录
没有效果,仍然停留在 mylogin.html这个登录页。
问题原因:指定了登录页面,但是没有指定 处理登录逻辑的 url地址
解决方式修改配置文件
2.5表单字段不一致问题

①解决方式1:将字段名成换成username、password
②解决方式2:修改SpringSecurity在登录时获取的参数名称
2.6还是登录 不了
2.7登录失败后的逻辑
默认逻辑是跳转到 mylogin?error页面
设置一个登录失败处理器
@Componentpublic class MyLoginFailureHandler implements AuthenticationFailureHandler {@Overridepublic void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {response.getWriter().println("登录失败");}}
2.8登录成功后的逻辑
默认是跳转回原页面、或者回到 主页面(index.html)
配置
@Componentpublic class MyLoginSuccessHandler implements AuthenticationSuccessHandler {@Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {response.setCharacterEncoding("UTF-8");response.getWriter().println("登录成功");}}
3.自定义登录逻辑
在真实的场景中,项目会有一个用户信息,里面有用户的密码,用户名登录信息。这些信息一定是从数据库中取得的。
3.1原始SpringSecurity框架在我们点击登录后为我们做了什么
1.首先进入 UsernamePasswordAuthenticationFilter 的 public ``Authentication ``attemptAuthentication``_(_``HttpServletRequest request``,``      ``HttpServletResponse response``_) _``throws ``AuthenticationException 的方法中。方法做了以下事情
①获取用户名、密码
②生成UsernamePasswordAuthenticationToken
③调用 AuthenticationManager去认证这个  UnamepwdAuthenToken
2.Authentication的实现类(ProviderManager),执行自己的 public Authentication authenticate(Authentication authentication) ,这个方法中做了以下事务
①获取这个 unamepwdToken的字节码对象
②寻找一个可以认证这个 unamepwdToken的 Provider
③调用provider的认证方法,返回Authenticaiton对象
3.Provider是进行unamepwdToken的验证,其中一个实现类(RemoteAuthenticationProvider)provider的support方法用来判断unamepwdtokne是否是我所能够处理的类型。接下来看下Provider的处理方法:
①从unametoken中去得用户名
②从Credentials中去得用户的密码
③通过认证 Manager中尝试授权,获取 角色集合(这里用的就是 UserDetailService,并返回一个UserDetail对象)
④将用户名密码、和角色重新封装成  unamepwdToken
4.UserDetailService提供的就是根据用户名查询 用户角色的功能,并返回一个角色的集合的方法
3.2需求描述
1.query方法需要有Admin角色才能够访问,
2.数据库中有 sysUser表和role表
3.重写UserDetailService和UserDetail
3.3角色设置了,不起作用的原因
3.4三种权限注解
①JSR-250注解:@DenyAll @RoleAllows()@PermitAll
②。。。
4.图片验证码
1.设置前置过滤器进行校验
2.实现认证失败处理类,完成认证失败时的返回
5.自定义登录逻辑
模仿智联招聘登录,用户仅凭手机号和验证码就可以实现登录
①短信验证码,使用图形验证码模拟
②框架登录逻辑需要密码比对
5.1编写处理短信验证码的过滤器
5.2编写SmsToken
5.3编写Provider
5.4编写在Provider中使用的UserDetailService以及UserDetail
在provider中的authenticate方法中会调用 userDetailService的loginByusername,返回userDetail
6.用户名密码登录的逻辑流程(源码级别)

1.登录请求进入UsernamePasswordAuthenticationFilter中。
2.获取用户名、密码封装成一个未认证的  token
3.将token放入 认证管理中 进行认证 
4.认证管理器的一个实现类(providerManager)的authenticate方法
5.providermanager选择一个支持这种token的Provider进行校验
6.用户密码选择 了一个  DaoAuthenticationProvider(实现了AbstractUserDetailsAuthenticationProvider)的一个实体类
7.DaoAuthenticationProvider中的  authenticate方法做了:
①从token的principles字段获取用户名
String username = (authentication.getPrincipal() == null) ? "NONE_PROVIDED": authentication.getName();
②先尝试从缓存中获取
③调用retriveuser方法
protected final UserDetails retrieveUser(String username,UsernamePasswordAuthenticationToken authentication)throws AuthenticationException {prepareTimingAttackProtection();try {//通过username查询用户的 信息 (UserDetail)UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username);if (loadedUser == null) {throw new InternalAuthenticationServiceException("UserDetailsService returned null, which is an interface contract violation");}//返回UserDetail信息return loadedUser;}catch (UsernameNotFoundException ex) {mitigateAgainstTimingAttack(authentication);throw ex;}catch (InternalAuthenticationServiceException ex) {throw ex;}catch (Exception ex) {throw new InternalAuthenticationServiceException(ex.getMessage(), ex);}}
④通过preAuthenticationChecks检查用户是否过期,禁用之类
preAuthenticationChecks.check(user);
⑤additionalAuthenticationChecks 密码校验
// 从数据库中查询的信息,token信息additionalAuthenticationChecks(user,(UsernamePasswordAuthenticationToken) authentication);==============================================================================protected void additionalAuthenticationChecks(UserDetails userDetails,UsernamePasswordAuthenticationToken authentication)throws AuthenticationException {String presentedPassword = authentication.getCredentials().toString();//若密码不匹配if (!passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {logger.debug("Authentication failed: password does not match stored value");throw new BadCredentialsException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials","Bad credentials"));}}
⑥返回一个Tokne,pricipal就是 从数据库中查询的userDetail,authentication是原始token,从中去得密码,user也是userDetail查询的。
7.Oauth2.0授权码模式
这里插入一条关于权限注解的相关内容,使用注解时,不要再用http.对请求进行指定了。
7.1项目搭建
1.pom文件导入
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-oauth2</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency>
2.Security配置文件
@EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled = true,jsr250Enabled = true)public class SecurityConfig extends WebSecurityConfigurerAdapter {}
3.认证服务器配置文件
@Configuration@EnableAuthorizationServerpublic class AuthorizationServerConfig {}
4.controller的几个方法
@RestControllerpublic class UserController {/*** 回调方法* @param code* @return*/@RequestMapping("getCode")public String getCode(String code){return code;}}
5.配置文件
security:oauth2:client:client-id: yurunclient-secret: yurunregistered-redirect-uri: http://localhost:8080/getCodescope: all
7.2运行步骤
1.通过浏览器访问(http://localhost:8080/oauth/authorize?response_type=code&client_id=yurun&redirct_uri=http://localhost:8080/getCode&scope=all)
2.跳转到登录页面,并完成登录
3.输入用户名和密码,会跳转到 getcode接口,并携带一个code
4.请求token

5.返回的结果
{"access_token": "abe04eb7-5dbe-4bb5-8606-68049436cdb4","token_type": "bearer","refresh_token": "03e96129-f94f-4537-bb00-d4eeb56c1022","expires_in": 43199,"scope": "all"}
8.密码模式
8.1请求token

8.2报错
8.3对SecurityConfig配置类修改
@Bean@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}

9.资源服务器的配置
9.1在认证服务器上同时设有资源服务器
@Configuration@EnableResourceServerpublic class ResourceServerConfig {}
9.2产生问题
资源服务器的存在会让其服务器上的所有接口需要令牌反问,当然包括 login接口。所以我们需要设置login接口。被允许
@Configuration@EnableResourceServerpublic class ResourceServerConfig extends ResourceServerConfigurerAdapter {@Overridepublic void configure(HttpSecurity http) throws Exception {http.formLogin().and().authorizeRequests().antMatchers("/login").permitAll();}}


