Spring Security入门(十七)-个性化用户认证流程(一)

一.导学
  • 自定义登录页面
  • 自定义登录成功处理器
  • 自定义登录失败处理器
二.自定义登录页面
  • loginPage方法:指定登录页面的url
@Override
    protected void configure(HttpSecurity http) throws Exception {

         http.formLogin()//form表单 高版本中默认是表单 低版本中默认是HttpBasic
                 .loginPage("/playmaker-signIn.html") //指定登录页面的url
                 //httpBasic() //httpBasic
                 .and()
                 //对请求授权配置
                 .authorizeRequests()
                 .anyRequest()//对任意请求都必须是已认证才能访问
                 .authenticated();
    }

在这里插入图片描述

  • playmaker-signIn.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>标准登录页面</title>
</head>
<body>
     <h1>标准登录页面</h1>
     <form action="/authentication/form" method="post">
          <table>
               <tr>
                   <td>用户名:</td>
                   <td><input type="text" name="username"></td>
               </tr>
              <tr>
                  <td>密码:</td>
                  <td><input type="password" name="password"></td>
              </tr>
              <tr>
                  <td colspan="2">
                      <button type="submit">登录</button>
                  </td>
              </tr>
          </table>
     </form>
</body>
</html>
  • 这里写的处理请求路径是自定义的,表单登录是由UsernamePasswordAuthenticationFilter控制的 它控制的是login POST请求,所以加条代码
 @Override
    protected void configure(HttpSecurity http) throws Exception {

         http.formLogin()//form表单 高版本中默认是表单 低版本中默认是HttpBasic
                 .loginPage("/playmaker-signIn.html") //指定登录页面的url
                 .loginProcessingUrl("/authentication/form") //指定处理登录请求的url
                 //httpBasic() //httpBasic
                 .and()
                 //对请求授权配置
                 .authorizeRequests()
                 .anyRequest()//对任意请求都必须是已认证才能访问
                 .authenticated();
    }
  • 访问登录页会出现这个问题,因为你后边的代码,任何请求都需要认证,包括你的登录页面,于是又跳到自己页面去了,不断死循环去了
    在这里插入图片描述
 @Override
    protected void configure(HttpSecurity http) throws Exception {

         http.formLogin()//form表单 高版本中默认是表单 低版本中默认是HttpBasic
                 .loginPage("/playmaker-signIn.html") //指定登录页面的url
                 .loginProcessingUrl("/authentication/form") //指定处理登录请求的url
                 //httpBasic() //httpBasic
                 .and()
                 //对请求授权配置
                 .authorizeRequests()
                 .antMatchers("/playmaker-signIn.html").permitAll()//当访问这个url时不需要身份认证
                 .anyRequest()//对任意请求都必须是已认证才能访问
                 .authenticated();
    }
  • 视频中此时访问登陆进去会报错403,关于csrf 跨站请求的东西(后边会讲)
  • 然而我们并没有出现这个问题,但还是把它关了吧,完整配置代码如下
@Override
    protected void configure(HttpSecurity http) throws Exception {

         http.formLogin()//form表单 高版本中默认是表单 低版本中默认是HttpBasic
                 .loginPage("/playmaker-signIn.html") //指定登录页面的url
                 .loginProcessingUrl("/authentication/form") //指定处理登录请求的url 会认为必须是跳转到我们自己写的这个真是存在的控制器里面, 
实际上这个路径对应的控制器不存在也没有关系。因为不会走。这里看起来更像是对security默认/login路径的重命名
                 //httpBasic() //httpBasic
                 .and()
                 //对请求授权配置
                 .authorizeRequests()
                 .antMatchers("/playmaker-signIn.html").permitAll()//当访问这个url时不需要身份认证
                 .anyRequest()//对任意请求都必须是已认证才能访问
                 .authenticated()
                 .and()
                 .csrf().disable();//关闭csrf
    }

此时访问OK
在这里插入图片描述
但是这里有两个问题

  • 我们发的是RESTful请求 如果这个请求需要身份认证 那么返回去的是一段html 这个是不合理的 RESTful服务返回去得应该是状态码和json信息,但是现在实际上是html(如果是html请求跳到登录页上 如果不是就返回一段json对象)
  • 虽然写了一个标准登陆页面 但我们的目标是写一个可重用的安全模块 意味着多个项目要运行这个安全模块 如何让使用这个安全模块的项目能够自定义这个模块 不用的时候才用你这个标准安全模块
三.处理不同类型的请求

在这里插入图片描述

@RestController
public class BorowserSecurityController {

    private Logger logger = LoggerFactory.getLogger(getClass());

    private RequestCache requestCache = new HttpSessionRequestCache();//跳转之前spring security用HttpSessionRequestCache这个类把当前请求缓存到这个session里面去 所以当我们跳转到authentication/require这个请求时我们可以用这个类,从session中把之前缓存的请求拿出来


    @Autowired
    private SecurityProperties securityProperties;
    @RequestMapping("/authentication/require")
    @ResponseStatus(code= HttpStatus.UNAUTHORIZED) //401
    public SimpleResponse authenticationrequire(HttpServletRequest request, HttpServletResponse response) throws IOException {
        SavedRequest savedRequest = requestCache.getRequest(request,response);//SavedRequest就是之前缓存的请求
        if(savedRequest!=null){
            String redirectUrl = savedRequest.getRedirectUrl();
            logger.info("跳转的地址:"+redirectUrl);
            if(StringUtils.endsWithIgnoreCase(redirectUrl,".html")){
                   redirectStrategy.sendRedirect(request,response,"");//这个跳转url是第二个要处理的问题
            }

        }
        return new SimpleResponse("访问的服务需要身份认证,请引导用户到登录页");
    }
}
  • SimpleResponse 类只是一个返回结果的信息类
public class SimpleResponse {
     private Object content;//定义成Object可以返回任何数据类型

    public SimpleResponse(Object content) {
        this.content = content;
    }

    public Object getContent() {
        return content;
    }

    public void setContent(Object content) {
        this.content = content;
    }
}
  • 我们把登录页面url换成/authentication/require
@Override
    protected void configure(HttpSecurity http) throws Exception {

         http.formLogin()//form表单 高版本中默认是表单 低版本中默认是HttpBasic
                 .loginPage("/authentication/require") //指定登录页面的url
                 .loginProcessingUrl("/authentication/form") //指定处理登录请求的url
                 //httpBasic() //httpBasic
                 .and()
                 //对请求授权配置
                 .authorizeRequests()
                 .antMatchers("/playmaker-signIn.html",
                         "/authentication/require").permitAll()//当访问这个url时不需要身份认证
                 .anyRequest()//对任意请求都必须是已认证才能访问
                 .authenticated()
                 .and()
                 .csrf().disable();//关闭csrf
    }
四.自定义安全模块
  • 让用户配置自己登录页面
  • application.properties
playmaker.security.browser.loginPage = /demo-signIn.html
  • demo-signIn.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Demo登录页</title>
</head>
<body>
       <h1>Demo登录页</h1>
</body>
</html>

在这里插入图片描述

  • BrowserProperties 浏览器相关的配置项

  • ValidateCodeProperties 验证码相关的

  • OAuth2Properties OAuth配置

  • SocialProperties Social配置

  • 由于这些配置类是 app 和 browser 项目公用的,写在core里面

@ConfigurationProperties( prefix = "playmaker.security")//读取配置中配置名为playmaker.security的项目项
public class SecurityProperties {
    private BrowserProperties browser = new BrowserProperties();

    public BrowserProperties getBrowser() {
        return browser;
    }

    public void setBrowser(BrowserProperties browser) {
        this.browser = browser;
    }
}
public class BrowserProperties {

    private String loginPage = "/playmaker-signIn.html";//默认配置

    public String getLoginPage() {
        return loginPage;
    }

    public void setLoginPage(String loginPage) {
        this.loginPage = loginPage;
    }
}
  • 为了职责分离,单独写一个入口被扫描开启的配置类
@Configuration
@EnableConfigurationProperties(SecurityProperties.class)//EnableConfigurationProperties 的作用是标明加载哪一个类 这效果和直接在目标类上写上@Configuration效果一样
public class SecurityCoreConfig {
}

  • 不要忘记放行了
@RestController
public class BorowserSecurityController {

    private Logger logger = LoggerFactory.getLogger(getClass());

    private RequestCache requestCache = new HttpSessionRequestCache();//跳转之前spring security用HttpSessionRequestCache这个类把当前请求缓存到这个session里面去 所以当我们跳转到authentication/require这个请求时我们可以用这个类,从session中把之前缓存的请求拿出来

    private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();//spring中的跳转工具

    @Autowired
    private SecurityProperties securityProperties;//注入
    
    @RequestMapping("/authentication/require")
    @ResponseStatus(code= HttpStatus.UNAUTHORIZED) //401
    public SimpleResponse authenticationrequire(HttpServletRequest request, HttpServletResponse response) throws IOException {
        SavedRequest savedRequest = requestCache.getRequest(request,response);//SavedRequest就是之前缓存的请求
        if(savedRequest!=null){
            String redirectUrl = savedRequest.getRedirectUrl();
            logger.info("跳转的地址:"+redirectUrl);
            if(StringUtils.endsWithIgnoreCase(redirectUrl,".html")){
                   redirectStrategy.sendRedirect(request,response,securityProperties.getBrowser().getLoginPage());//注入url
            }

        }
        return new SimpleResponse("访问的服务需要身份认证,请引导用户到登录页");
    }
}
 	@Autowired
    private SecurityProperties securityProperties;//注入

	@Override
    protected void configure(HttpSecurity http) throws Exception {

         http.formLogin()//form表单 高版本中默认是表单 低版本中默认是HttpBasic
                 .loginPage("/authentication/require") //指定登录页面的url
                 .loginProcessingUrl("/authentication/form") //指定处理登录请求的url
                 //httpBasic() //httpBasic
                 .and()
                 //对请求授权配置
                 .authorizeRequests()
                 .antMatchers("/playmaker-signIn.html",
                         "/authentication/require",
                         securityProperties.getBrowser().getLoginPage()).permitAll()//当访问这个url时不需要身份认证
                 .anyRequest()//对任意请求都必须是已认证才能访问
                 .authenticated()
                 .and()
                 .csrf().disable();//关闭csrf
    }
  • 运行效果如下
    在这里插入图片描述
  • 访问index.html(因为你自定义登录页面)
    在这里插入图片描述
  • 没有自定义,访问index.html跳转到标准登陆页面
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值