zoukankan      html  css  js  c++  java
  • 013 个性化用户认证流程

    一:任务

    1.任务

      自定义登录页面

      自定义登录成功处理

      自定义登录失败处理

    二:自定义登录页面

    1.说明

      在security中,默认的登录处理是

      

    2.BrowserSecurityConfig

      这里从新定义登录的页面,与登录方法

     1 package com.cao.security.browser;
     2 
     3 import org.springframework.context.annotation.Bean;
     4 import org.springframework.context.annotation.Configuration;
     5 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
     6 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
     7 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
     8 import org.springframework.security.crypto.password.PasswordEncoder;
     9 /**
    10  * 覆盖掉security原有的配置
    11  * @author dell
    12  *
    13  */
    14 @Configuration
    15 public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter{
    16     @Override
    17     protected void configure(HttpSecurity http) throws Exception {
    18         //表单登陆的一个安全认证环境
    19         http.formLogin()
    20             .loginPage("/index.html")
    21             .loginProcessingUrl("/authentication/form")
    22 //        http.httpBasic()
    23             .and()
    24             .authorizeRequests()    //请求授权
    25             .antMatchers("/index.html").permitAll()  //这个url不需要认证
    26             .anyRequest()            //任何请求
    27             .authenticated()         //都需要认证
    28             .and()
    29             .csrf().disable();      //去掉csrf的防护
    30         
    31     }
    32     
    33     @Bean
    34     public PasswordEncoder passwordEncoder() {
    35         return new BCryptPasswordEncoder();
    36     }
    37 }

    3.index.htnl

     1 <!DOCTYPE html>
     2 <html>
     3 <head>
     4 <meta charset="UTF-8">
     5 <title>登录</title>
     6 </head>
     7 <body>
     8     <h2>标准登录页面</h2>
     9     <h3>表单登录</h3>
    10     <form action="/authentication/form" method="post">
    11         <table>
    12             <tr>
    13                 <td>用户名</td>
    14                 <td><input type="text" name="username"></td>
    15             </tr>
    16             <tr>
    17                 <td>密码</td>
    18                 <td><input type="password" name="password"></td>
    19             </tr>
    20             <tr>
    21                 <td colspan="2"><button type="submit">登录</button></td>
    22             </tr>
    23         </table>
    24     </form>
    25 </body>
    26 </html>

    4.登录界面

      

    三:优化

    1.问题

      现在的处理是接收到html请求,然后直接跳转到了html登录页面

      因为,这里优化一下比较好,做到统一处理。

      现在的优化方法如下:

      

    2.先修改配置类

      这里说明,进入的显示控制类,然后由控制类进行决定走哪里

      这里还包含了自定义的url不进过认证,这里的程序先粘贴过来了。

     1 package com.cao.security.browser;
     2 
     3 import org.springframework.beans.factory.annotation.Autowired;
     4 import org.springframework.context.annotation.Bean;
     5 import org.springframework.context.annotation.Configuration;
     6 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
     7 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
     8 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
     9 import org.springframework.security.crypto.password.PasswordEncoder;
    10 
    11 import com.cao.security.core.properties.SecurityProperties;
    12 /**
    13  * 覆盖掉security原有的配置
    14  * @author dell
    15  *
    16  */
    17 @Configuration
    18 public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter{
    19     @Autowired
    20     private SecurityProperties securityProperties;
    21     
    22     @Override
    23     protected void configure(HttpSecurity http) throws Exception {
    24         //表单登陆的一个安全认证环境
    25         http.formLogin()
    26             .loginPage("/authentication/require")
    27             .loginProcessingUrl("/authentication/form")
    28 //        http.httpBasic()
    29             .and()
    30             .authorizeRequests()    //请求授权
    31             .antMatchers("/authentication/require",
    32                     securityProperties.getBrowser().getLoginPage()).permitAll()  //这个url不需要认证,包含自定义的登录页
    33             .anyRequest()            //任何请求
    34             .authenticated()         //都需要认证
    35             .and()
    36             .csrf().disable();      //去掉csrf的防护
    37         
    38     }
    39     
    40     @Bean
    41     public PasswordEncoder passwordEncoder() {
    42         return new BCryptPasswordEncoder();
    43     }
    44 }

    3.控制类

      这里直接读取的是可以自定义的页面,后续会添加如何引入的。

     1 /**
     2  * 
     3  */
     4 package com.cao.security.browser;
     5 
     6 import java.io.IOException;
     7 
     8 import javax.servlet.http.HttpServletRequest;
     9 import javax.servlet.http.HttpServletResponse;
    10 
    11 import org.apache.commons.lang.StringUtils;
    12 import org.slf4j.Logger;
    13 import org.slf4j.LoggerFactory;
    14 import org.springframework.beans.factory.annotation.Autowired;
    15 import org.springframework.http.HttpStatus;
    16 import org.springframework.security.web.DefaultRedirectStrategy;
    17 import org.springframework.security.web.RedirectStrategy;
    18 import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
    19 import org.springframework.security.web.savedrequest.RequestCache;
    20 import org.springframework.security.web.savedrequest.SavedRequest;
    21 import org.springframework.web.bind.annotation.RequestMapping;
    22 import org.springframework.web.bind.annotation.ResponseStatus;
    23 import org.springframework.web.bind.annotation.RestController;
    24 
    25 import com.cao.security.browser.support.SimpleResponse;
    26 import com.cao.security.core.properties.SecurityProperties;
    27 
    28 /**
    29  * @author dell
    30  *
    31  */
    32 @RestController
    33 public class BrowserSecurityController {
    34     private Logger logger=LoggerFactory.getLogger(getClass());
    35     //拿到引气身份跳转的请求
    36     //因为在跳转之前,security会将请求缓存到session中
    37     private RequestCache requestCache=new HttpSessionRequestCache();
    38     
    39     //跳转
    40     private RedirectStrategy redirectStrategy=new DefaultRedirectStrategy();
    41     
    42     //方便读取自定义登录页的配置项
    43     @Autowired
    44     private SecurityProperties securityProperties;
    45 
    46     /**
    47      * 当需要身份认证的时候,跳转到这里
    48      * @param request
    49      * @param response
    50      * @return
    51      * @throws Exception 
    52      */
    53     @RequestMapping("/authentication/require")
    54     @ResponseStatus(code=HttpStatus.UNAUTHORIZED)
    55     public SimpleResponse requiredAuthentication(HttpServletRequest request,HttpServletResponse response) throws Exception {
    56         SavedRequest saveRequest=requestCache.getRequest(request, response);
    57         if(saveRequest!=null) {
    58             String target=saveRequest.getRedirectUrl();
    59             logger.info("引发跳转的请求:"+target);
    60             if(StringUtils.endsWithIgnoreCase(target, ".html")) {
    61                 //跳转到一个自定义的登录页
    62                 redirectStrategy.sendRedirect(request, response, securityProperties.getBrowser().getLoginPage());
    63             }
    64         }
    65         return new SimpleResponse("访问的服务需要身份认证,请引导到登录页");
    66     }
    67 }

       返回值,需要一个类。SimpleResponse.java

     1 package com.cao.security.browser.support;
     2 
     3 public class SimpleResponse {
     4     public SimpleResponse(Object content) {
     5         this.content=content;
     6     }
     7     
     8     private Object content;
     9 
    10     public Object getContent() {
    11         return content;
    12     }
    13 
    14     public void setContent(Object content) {
    15         this.content = content;
    16     }
    17     
    18 }

    4.系统配置封装

      方便统一管理用户的配置项。

      

    5.新建SecurityProperties

      这里是最外层的一层包装

      同时。这里需要放入在core的项目下。

      

      首先,这里会读取的是jun.security开头的配置项,同时会把配置项的第三个字段读取到同browser相同的类中。所以,后续还要写browser的类。

     1 package com.cao.security.core.properties;
     2 
     3 import org.springframework.boot.context.properties.ConfigurationProperties;
     4 
     5 @ConfigurationProperties(prefix="jun.security")
     6 public class SecurityProperties {
     7     private BrowserProperties browser=new BrowserProperties();
     8 
     9     public BrowserProperties getBrowser() {
    10         return browser;
    11     }
    12 
    13     public void setBrowser(BrowserProperties browser) {
    14         this.browser = browser;
    15     }
    16 
    17     
    18 }

    6.BrowserProperties.java

      这里要读取的是配置项的第四个字段,这里需要的是不能乱写。

      loginPage这里有一个默认值,如果用户没有给,就使用初始化的值。

     1 package com.cao.security.core.properties;
     2 
     3 public class BrowserProperties {
     4 
     5     private String loginPage="/index.html";
     6 
     7     public String getLoginPage() {
     8         return loginPage;
     9     }
    10 
    11     public void setLoginPage(String loginPage) {
    12         this.loginPage = loginPage;
    13     }
    14     
    15 }

    7.SecurityConfig.java

      这里是的配置项的类生效,这里的类写最外层的即可。

     1 package com.cao.security.core.properties;
     2 
     3 import org.springframework.boot.context.properties.EnableConfigurationProperties;
     4 import org.springframework.context.annotation.Configuration;
     5 
     6 @Configuration
     7 //让SecurityProperties读取器生效
     8 @EnableConfigurationProperties(SecurityProperties.class)
     9 public class SecurityCoreConfig {
    10 
    11 }

    8.自定义的配置项

      这里写在demo项目中。

     1 ##JDBC
     2 spring.datasource.driver-class-name = com.mysql.jdbc.Driver
     3 spring.datasource.url= jdbc:mysql://127.0.0.1:3308/test?useUnicode=yes&characterEncoding=UTF-8&useSSL=false
     4 spring.datasource.username = root
     5 spring.datasource.password = 123456
     6 
     7 ##session store type
     8 spring.session.store-type=none
     9 
    10 ##server port
    11 #server.port=8060
    12 
    13 ##security login
    14 #security.basic.enabled = false
    15 
    16 jun.security.browser.loginPage=/newIndex.html

    9.效果

      访问:http://localhost:8080/user/

      

      访问:newIndex.html

      

      访问:http://localhost:8080/index.html

      

    四:登录成功后的处理

    1.修改初始化的配置

      主要是说明登录成功后使用自定义的类

     1 package com.cao.security.browser;
     2 
     3 import org.springframework.beans.factory.annotation.Autowired;
     4 import org.springframework.context.annotation.Bean;
     5 import org.springframework.context.annotation.Configuration;
     6 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
     7 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
     8 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
     9 import org.springframework.security.crypto.password.PasswordEncoder;
    10 import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
    11 
    12 import com.cao.security.browser.authentication.BrowserAuthenticationSucceswsHandler;
    13 import com.cao.security.core.properties.SecurityProperties;
    14 /**
    15  * @Description 覆盖掉security原有的配置
    16  * @author dell
    17  *
    18  */
    19 @Configuration
    20 public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter{
    21     //获取自定义的登录页面
    22     @Autowired
    23     private SecurityProperties securityProperties;
    24     
    25     //使用自己的登录成功后的处理类
    26     @Autowired
    27     private AuthenticationSuccessHandler browserAuthenticationSucceswsHandler;
    28     
    29     
    30     @Override
    31     protected void configure(HttpSecurity http) throws Exception {
    32         //表单登陆的一个安全认证环境
    33         http.formLogin()
    34             .loginPage("/authentication/require")
    35             .loginProcessingUrl("/authentication/form")
    36             .successHandler(browserAuthenticationSucceswsHandler)
    37 //        http.httpBasic()
    38             .and()
    39             .authorizeRequests()    //请求授权
    40             .antMatchers("/authentication/require",
    41                     securityProperties.getBrowser().getLoginPage()).permitAll()  //这个url不需要认证,包含自定义的登录页
    42             .anyRequest()            //任何请求
    43             .authenticated()         //都需要认证
    44             .and()
    45             .csrf().disable();      //去掉csrf的防护
    46         
    47     }
    48     
    49     @Bean
    50     public PasswordEncoder passwordEncoder() {
    51         return new BCryptPasswordEncoder();
    52     }
    53 }

    2.登录成功处理类

     1 package com.cao.security.browser.authentication;
     2 
     3 import java.io.IOException;
     4 
     5 import javax.servlet.ServletException;
     6 import javax.servlet.http.HttpServletRequest;
     7 import javax.servlet.http.HttpServletResponse;
     8 
     9 import org.slf4j.Logger;
    10 import org.slf4j.LoggerFactory;
    11 import org.springframework.beans.factory.annotation.Autowired;
    12 import org.springframework.security.core.Authentication;
    13 import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
    14 import org.springframework.stereotype.Component;
    15 
    16 import com.fasterxml.jackson.databind.ObjectMapper;
    17 
    18 @Component(value="browserAuthenticationSucceswsHandler")
    19 public class BrowserAuthenticationSucceswsHandler implements AuthenticationSuccessHandler {
    20     private Logger logger=LoggerFactory.getLogger(getClass());
    21     
    22     @Autowired
    23     private ObjectMapper objectMapper;
    24 
    25     /**
    26      * @Description 登录成功会被调用
    27      */
    28     @Override
    29     public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
    30             Authentication authentication) throws IOException, ServletException {
    31         //Authentication 封装了认证信息
    32         logger.info("登录成功");
    33         response.setContentType("application/json;charset=UTF-8");
    34         //将authentication转为json字符串
    35         response.getWriter().write(objectMapper.writeValueAsString(authentication));
    36     }
    37 
    38 }

    3.效果

      登录成功后的authentication的json格式如下:

      

    五:登录失败后的处理

    1.修改初始化的配置

     1 package com.cao.security.browser;
     2 
     3 import org.springframework.beans.factory.annotation.Autowired;
     4 import org.springframework.context.annotation.Bean;
     5 import org.springframework.context.annotation.Configuration;
     6 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
     7 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
     8 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
     9 import org.springframework.security.crypto.password.PasswordEncoder;
    10 import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
    11 
    12 import com.cao.security.browser.authentication.BrowserAuthenticationFailHandler;
    13 import com.cao.security.browser.authentication.BrowserAuthenticationSucceswsHandler;
    14 import com.cao.security.core.properties.SecurityProperties;
    15 /**
    16  * @Description 覆盖掉security原有的配置
    17  * @author dell
    18  *
    19  */
    20 @Configuration
    21 public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter{
    22     //获取自定义的登录页面
    23     @Autowired
    24     private SecurityProperties securityProperties;
    25     
    26     //使用自己的登录成功后的处理类
    27     @Autowired
    28     private AuthenticationSuccessHandler browserAuthenticationSucceswsHandler;
    29     
    30     //使用自己的登录失败后的处理类
    31     @Autowired
    32     private BrowserAuthenticationFailHandler browserAuthenticationFailHandler;
    33     
    34     @Override
    35     protected void configure(HttpSecurity http) throws Exception {
    36         //表单登陆的一个安全认证环境
    37         http.formLogin()
    38             .loginPage("/authentication/require")
    39             .loginProcessingUrl("/authentication/form")
    40             .successHandler(browserAuthenticationSucceswsHandler)
    41             .failureHandler(browserAuthenticationFailHandler)
    42 //        http.httpBasic()
    43             .and()
    44             .authorizeRequests()    //请求授权
    45             .antMatchers("/authentication/require",
    46                     securityProperties.getBrowser().getLoginPage()).permitAll()  //这个url不需要认证,包含自定义的登录页
    47             .anyRequest()            //任何请求
    48             .authenticated()         //都需要认证
    49             .and()
    50             .csrf().disable();      //去掉csrf的防护
    51         
    52     }
    53     
    54     @Bean
    55     public PasswordEncoder passwordEncoder() {
    56         return new BCryptPasswordEncoder();
    57     }
    58 }

    2.失败控制类

     1 package com.cao.security.browser.authentication;
     2 
     3 import java.io.IOException;
     4 
     5 import javax.servlet.ServletException;
     6 import javax.servlet.http.HttpServletRequest;
     7 import javax.servlet.http.HttpServletResponse;
     8 
     9 import org.slf4j.Logger;
    10 import org.slf4j.LoggerFactory;
    11 import org.springframework.beans.factory.annotation.Autowired;
    12 import org.springframework.http.HttpStatus;
    13 import org.springframework.security.core.AuthenticationException;
    14 import org.springframework.security.web.authentication.AuthenticationFailureHandler;
    15 import org.springframework.stereotype.Component;
    16 
    17 import com.fasterxml.jackson.databind.ObjectMapper;
    18 /**
    19  * @Description 登录失败后的处理
    20  * @author dell
    21  *
    22  */
    23 @Component(value="browserAuthenticationFailHandler")
    24 public class BrowserAuthenticationFailHandler implements AuthenticationFailureHandler {
    25     private Logger logger=LoggerFactory.getLogger(getClass());
    26     
    27     @Autowired
    28     private ObjectMapper objectMapper;
    29 
    30     @Override
    31     public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
    32             AuthenticationException exception) throws IOException, ServletException {
    33         //这里不会有Authentication
    34         logger.info("登录失败");
    35         response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
    36         response.setContentType("application/json;charset=UTF-8");
    37         response.getWriter().write(objectMapper.writeValueAsString(exception));
    38 
    39     }
    40 
    41 }

    3.效果

      

    六:优化

    1.问题

      返回的只是json格式的信息

      因为有时候,前端是模板语言的形式

      所以,要继续优化,让返回的可以是js0n,也可以是返回的跳转。

    2.定义一个枚举

      包含redirect,json

    1 package com.cao.security.core.properties;
    2 
    3 public enum LoginType {
    4     REDIRECT,
    5     JSON;
    6 }

    3.读取器

      添加一个字段

     1 package com.cao.security.core.properties;
     2 
     3 public class BrowserProperties {
     4 
     5     private String loginPage="/index.html";
     6     
     7     private LoginType loginType=LoginType.JSON;
     8 
     9     public String getLoginPage() {
    10         return loginPage;
    11     }
    12 
    13     public void setLoginPage(String loginPage) {
    14         this.loginPage = loginPage;
    15     }
    16 
    17     public LoginType getLoginType() {
    18         return loginType;
    19     }
    20 
    21     public void setLoginType(LoginType loginType) {
    22         this.loginType = loginType;
    23     }
    24     
    25 }

    4.成功处理处理器

      注意继承的类

     1 package com.cao.security.browser.authentication;
     2 
     3 import java.io.IOException;
     4 
     5 import javax.servlet.ServletException;
     6 import javax.servlet.http.HttpServletRequest;
     7 import javax.servlet.http.HttpServletResponse;
     8 
     9 import org.slf4j.Logger;
    10 import org.slf4j.LoggerFactory;
    11 import org.springframework.beans.factory.annotation.Autowired;
    12 import org.springframework.security.core.Authentication;
    13 import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
    14 import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
    15 import org.springframework.stereotype.Component;
    16 
    17 import com.cao.security.core.properties.LoginType;
    18 import com.cao.security.core.properties.SecurityProperties;
    19 import com.fasterxml.jackson.databind.ObjectMapper;
    20 /**
    21  * @Description 登录成功后的处理
    22  * @author dell
    23  *
    24  */
    25 @Component(value="browserAuthenticationSucceswsHandler")
    26 public class BrowserAuthenticationSucceswsHandler extends SavedRequestAwareAuthenticationSuccessHandler {
    27     private Logger logger=LoggerFactory.getLogger(getClass());
    28     
    29     @Autowired
    30     private ObjectMapper objectMapper;
    31     
    32     @Autowired
    33     private SecurityProperties securityProperties;
    34 
    35     /**
    36      * @Description 登录成功会被调用
    37      */
    38     @Override
    39     public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
    40             Authentication authentication) throws IOException, ServletException {
    41         //Authentication 封装了认证信息
    42         logger.info("登录成功");
    43         
    44         if(LoginType.JSON.equals(securityProperties.getBrowser().getLoginType())) {
    45             response.setContentType("application/json;charset=UTF-8");
    46             //将authentication转为json字符串
    47             response.getWriter().write(objectMapper.writeValueAsString(authentication));
    48         }else {
    49             //跳转
    50             super.onAuthenticationSuccess(request, response, authentication);
    51         }
    52         
    53         
    54     }
    55 
    56 }

    5.失败处理处理器

      注意继承的类

     1 package com.cao.security.browser.authentication;
     2 
     3 import java.io.IOException;
     4 
     5 import javax.servlet.ServletException;
     6 import javax.servlet.http.HttpServletRequest;
     7 import javax.servlet.http.HttpServletResponse;
     8 
     9 import org.slf4j.Logger;
    10 import org.slf4j.LoggerFactory;
    11 import org.springframework.beans.factory.annotation.Autowired;
    12 import org.springframework.http.HttpStatus;
    13 import org.springframework.security.core.AuthenticationException;
    14 import org.springframework.security.web.authentication.AuthenticationFailureHandler;
    15 import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
    16 import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
    17 import org.springframework.stereotype.Component;
    18 
    19 import com.cao.security.core.properties.LoginType;
    20 import com.cao.security.core.properties.SecurityProperties;
    21 import com.fasterxml.jackson.databind.ObjectMapper;
    22 /**
    23  * @Description 登录失败后的处理
    24  * @author dell
    25  *
    26  */
    27 @Component(value="browserAuthenticationFailHandler")
    28 public class BrowserAuthenticationFailHandler extends SimpleUrlAuthenticationFailureHandler {
    29     private Logger logger=LoggerFactory.getLogger(getClass());
    30     
    31     @Autowired
    32     private ObjectMapper objectMapper;
    33     
    34     @Autowired
    35     private SecurityProperties securityProperties;
    36 
    37     @Override
    38     public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
    39             AuthenticationException exception) throws IOException, ServletException {
    40         //这里不会有Authentication
    41         logger.info("登录失败");
    42         if(LoginType.JSON.equals(securityProperties.getBrowser().getLoginType())) {
    43             response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
    44             response.setContentType("application/json;charset=UTF-8");
    45             response.getWriter().write(objectMapper.writeValueAsString(exception));
    46         }else {
    47             //跳转
    48             super.onAuthenticationFailure(request, response, exception);
    49         }
    50     }
    51 
    52 }

    6.效果

      随意输入一个xxxxxx.html

      就可以跳转到了index.html登录页、

      

  • 相关阅读:
    Oracle三大设计范式
    数据库查询4
    Oracle 常用内置函数
    数据库查询2
    数据库查询练习1
    Oracle 建表
    线程1—Runnable
    线程1—Thread
    输入输出2
    输入输出1
  • 原文地址:https://www.cnblogs.com/juncaoit/p/9744781.html
Copyright © 2011-2022 走看看