日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

spring security认证

發(fā)布時(shí)間:2023/12/10 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 spring security认证 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1 開發(fā)基于表單的認(rèn)證

Spring security核心的功能

  • 認(rèn)證(你是誰(shuí)?)
  • 授權(quán)(你能干什么?)
  • 攻擊防護(hù)(防止偽造身份)

spring security實(shí)現(xiàn)了默認(rèn)的用戶名+密碼認(rèn)證,默認(rèn)用戶名為user,密碼為:

?

?

?spring security基本原理:過(guò)濾器鏈

?

?  對(duì)于UsernamePasswordAuthenticationFilter只會(huì)攔截 url為/login,method為POST的請(qǐng)求。

?1.1 自定義用戶認(rèn)證邏輯

1)處理用戶信息獲取邏輯

  UserDetailsService接口,只有一個(gè)方法:loadUserByUsername

實(shí)現(xiàn)該接口:數(shù)據(jù)庫(kù)中存放的是加密密碼,對(duì)于同一個(gè)密碼不同時(shí)間的加密密文不一樣

@Component public class MyUserDetailsService implements UserDetailsService {private Logger logger = LoggerFactory.getLogger(getClass());@Autowiredprivate PasswordEncoder passwordEncoder;@Overridepublic UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {logger.info("用戶名信息:" + s);// 根據(jù)用戶名查找用戶信息logger.info("數(shù)據(jù)庫(kù)密碼:" + passwordEncoder.encode("123456"));// 用戶名和密碼信息用來(lái)做認(rèn)證,權(quán)限信息用來(lái)對(duì)該用戶做授權(quán)return new User(s, "$2a$10$eFw06n0ABK2NFuse8y5f/eDUq7we26qQTceEtXSWNbMXnQ5Yf5Iha",AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));} }

?

?

2)處理用戶信息校驗(yàn)邏輯

?

  處理密碼加密解密:在配置文件中將PasswordEncoder對(duì)象注入spring容器,等價(jià)于@Component+包掃描組件

?

?

1.2 個(gè)性化用戶認(rèn)證流程

1)對(duì)于瀏覽器,返回自定義登錄頁(yè)面,讓UsernamePasswordXxxFilter來(lái)處理登錄請(qǐng)求;對(duì)于調(diào)用RESTful服務(wù),返回json錯(cuò)誤信息。

 ? 用戶登錄成功后 ,對(duì)于瀏覽器,返回需要的頁(yè)面;對(duì)于服務(wù),返回json數(shù)據(jù)。

?

?  權(quán)限配置:

@Overrideprotected void configure(HttpSecurity http) throws Exception {http.formLogin()// 表單登錄.loginPage("/authentication/require") //將登錄頁(yè)面重定向到controller.loginProcessingUrl("/authentication/form").and().authorizeRequests() //請(qǐng)求授權(quán).antMatchers("/authentication/require",securityProperties.getBrowser().getLoginPage()).permitAll()//該頁(yè)面允許通過(guò) .anyRequest().authenticated() // 其他資源需要認(rèn)證 .and().csrf().disable(); // 將跨站防護(hù)關(guān)掉}

?

  

  控制器,根據(jù)之前URL的路徑判斷是否為RESTful服務(wù),在處理

/* 當(dāng)客戶端發(fā)出請(qǐng)求,當(dāng)需要認(rèn)證時(shí),spring security會(huì)重定向到該控制器*/ @RestController public class BrowserSecurityController {private Logger logger = LoggerFactory.getLogger(getClass());// 請(qǐng)求緩存private RequestCache requestCache = new HttpSessionRequestCache();private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();@Autowiredprivate SecurityProperties securityProperties;/*** 當(dāng)需要身份認(rèn)證時(shí)跳轉(zhuǎn)到這里* @param request* @param response* @return*/@RequestMapping("/authentication/require")@ResponseStatus(code = HttpStatus.UNAUTHORIZED)public SimpleResponse requireAuthentication(HttpServletRequest request, HttpServletResponse response) throws IOException {// 判斷請(qǐng)求類型,HTML或者appSavedRequest savedRequest = requestCache.getRequest(request, response);if(savedRequest!=null){String targetUrl = savedRequest.getRedirectUrl();logger.info("引發(fā)跳轉(zhuǎn)的URL:"+targetUrl);// 如果之前的URL為.html結(jié)尾的URL,則重定向到登錄頁(yè)面if(StringUtils.endsWithIgnoreCase(targetUrl, ".html")){redirectStrategy.sendRedirect(request, response,securityProperties.getBrowser().getLoginPage());}}return new SimpleResponse("請(qǐng)求的服務(wù)需要身份認(rèn)證,請(qǐng)引導(dǎo)用戶到登錄頁(yè)面");} } BrowserSecurityController.java

?

?

  在啟動(dòng)項(xiàng)目中的application.properties文件中配置登錄頁(yè)面:

# 配置登錄頁(yè)面 getword.security.browser.loginPage=/demo.html

?

?

  讀取配置文件信息:

  

import org.springframework.boot.context.properties.ConfigurationProperties;// 讀取前綴為getword.security的屬性配置,其中browser中的屬性會(huì)被讀取到browserProperties中 @ConfigurationProperties(prefix = "getword.security") public class SecurityProperties {// browser的屬性會(huì)匹配getword.security.browser后面的屬性private BrowserProperties browser = new BrowserProperties();public BrowserProperties getBrowser() {return browser;}public void setBrowser(BrowserProperties browser) {this.browser = browser;} } SecurityProperties.java

?

?

public class BrowserProperties {private String loginPage = "/login.html"; //默認(rèn)值public String getLoginPage() {return loginPage;}public void setLoginPage(String loginPage) {this.loginPage = loginPage;} } BrowserProperties.java

?

?

@Configuration @EnableConfigurationProperties(SecurityProperties.class) //讓屬性配置讀取器生效 public class SecurityCodeConfig { }

?

?

2)自定義登錄成功處理,異步登錄,AuthenticationSuccessHandler接口

  自定義登錄成處理:

@Component("vstudyAuthenticationSuccessHandler") public class VstudyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {private Logger logger = LoggerFactory.getLogger(getClass());//工具類, 將對(duì)象轉(zhuǎn)成json @Autowiredprivate ObjectMapper objectMapper;// 登錄成功后調(diào)用 @Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {logger.info("登錄成功");response.setContentType("application/json;charset=utf-8");response.getWriter().write(objectMapper.writeValueAsString(authentication));} } VstudyAuthenticationSuccessHandler

  注冊(cè),使處理器生效:

?

?

3)登錄失敗處理

@Component("vstudyAuthenticationFailHandler") public class VstudyAuthenticationFailHandler implements AuthenticationFailureHandler {@Autowiredprivate ObjectMapper objectMapper;private Logger logger = LoggerFactory.getLogger(getClass());@Overridepublic void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,AuthenticationException e) throws IOException, ServletException {logger.info("登錄失敗");response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); //服務(wù)器內(nèi)部錯(cuò)誤response.setContentType("application/json;charset=utf-8");response.getWriter().write(objectMapper.writeValueAsString(e));} } VstudyAuthenticationFailHandler.java

?

配置:和success類似

?

4)判斷請(qǐng)求方式,做出相應(yīng)的處理

successHandler:

@Component("vstudyAuthenticationSuccessHandler") public class VstudyAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {private Logger logger = LoggerFactory.getLogger(getClass());//工具類, 將對(duì)象轉(zhuǎn)成json @Autowiredprivate ObjectMapper objectMapper;@Autowiredprivate SecurityProperties securityProperties; //獲取配置信息// 登錄成功后調(diào)用 @Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {logger.info("登錄成功");if(LoginType.JSON.equals(securityProperties.getBrowser().getLoginType())){response.setContentType("application/json;charset=utf-8");response.getWriter().write(objectMapper.writeValueAsString(authentication));}else{// 調(diào)用父類方法,完成重定向跳轉(zhuǎn)super.onAuthenticationSuccess(request, response, authentication);}} } VstudyAuthenticationSuccessHandler

?

failureHandler:

@Component("vstudyAuthenticationFailHandler") public class VstudyAuthenticationFailHandler extends SimpleUrlAuthenticationFailureHandler {@Autowiredprivate SecurityProperties securityProperties;@Autowiredprivate ObjectMapper objectMapper;private Logger logger = LoggerFactory.getLogger(getClass());@Overridepublic void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,AuthenticationException e) throws IOException, ServletException {logger.info("登錄失敗");if(LoginType.JSON.equals(securityProperties.getBrowser().getLoginType())){response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); //服務(wù)器內(nèi)部錯(cuò)誤response.setContentType("application/json;charset=utf-8");response.getWriter().write(objectMapper.writeValueAsString(e));}else{super.onAuthenticationFailure(request, response, e);}} } VstudyAuthenticationFailHandler

?

?

2 認(rèn)證流程

?

?

3 圖形驗(yàn)證碼

3.1 生成圖形驗(yàn)證碼

  驗(yàn)證碼圖片信息:

public class ImageCode {private BufferedImage image;private String code;private LocalDateTime expireTime;//過(guò)期時(shí)間public ImageCode(BufferedImage image, String code, int expireIn){this.image = image;this.code = code;this.expireTime = LocalDateTime.now().plusSeconds(expireIn);}public ImageCode(BufferedImage image, String code, LocalDateTime expireTime){this.image = image;this.code = code;this.expireTime = expireTime;} } ImageCode

?

?

  控制器:

@RestController public class ValidateCodeController {public static String SESSION_KEY = "SESSION_KEY_IMAGE_CODE";private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();@Autowiredprivate SecurityProperties securityProperties;@GetMapping("/image/code")public void createCode(HttpServletRequest request, HttpServletResponse response) throws IOException {ImageCode imageCode = createImageCode(new ServletWebRequest(request,response));sessionStrategy.setAttribute(new ServletWebRequest(request, response), SESSION_KEY, imageCode);ImageIO.write(imageCode.getImage(), "JPEG", response.getOutputStream());}/*** 生成ImageCode驗(yàn)證碼* @param request* @return*/public ImageCode createImageCode(ServletWebRequest request){// 生成驗(yàn)證碼,方法很多int width = 60;int height = 20;BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);Graphics g = image.getGraphics();Random random = new Random();g.setColor(getRandColor(200, 250));g.fillRect(0, 0, width, height);g.setFont(new Font("Times New Roman", Font.ITALIC, 20));g.setColor(getRandColor(160, 200));for (int i = 0; i < 155; i++) {int x = random.nextInt(width);int y = random.nextInt(height);int xl = random.nextInt(12);int yl = random.nextInt(12);g.drawLine(x, y, x + xl, y + yl);}String sRand = "";for (int i = 0; i < 4; i++) {String rand = String.valueOf(random.nextInt(10));sRand += rand;g.setColor(new Color(20 + random.nextInt(110), 20 + random.nextInt(110), 20 + random.nextInt(110)));g.drawString(rand, 13 * i + 6, 16);}g.dispose();return new ImageCode(image, sRand, 100);}/*** 生成隨機(jī)背景條紋** @param fc* @param bc* @return*/private Color getRandColor(int fc, int bc) {Random random = new Random();if (fc > 255) {fc = 255;}if (bc > 255) {bc = 255;}int r = fc + random.nextInt(bc - fc);int g = fc + random.nextInt(bc - fc);int b = fc + random.nextInt(bc - fc);return new Color(r, g, b);} } ValidateCodeController

?

?

3.2 驗(yàn)證碼校驗(yàn)

?自定義過(guò)濾器:

public class ValidateCodeFilter extends OncePerRequestFilter {/*** 驗(yàn)證碼校驗(yàn)失敗處理器*/private AuthenticationFailureHandler authenticationFailureHandler;/*** 系統(tǒng)配置信息*/private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();/*** 系統(tǒng)中的校驗(yàn)碼處理器*/@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {// 只處理登錄請(qǐng)求if (StringUtils.equals("/authetication/form", request.getRequestURI())&& StringUtils.equalsIgnoreCase(request.getMethod(), "POST")) {try {logger.info("驗(yàn)證碼校驗(yàn)通過(guò)");} catch (ValidateCodeException e) {//驗(yàn)證失敗 authenticationFailureHandler.onAuthenticationFailure(request, response, e);}}filterChain.doFilter(request, response);}protected void validate(ServletWebRequest request) throws ServletRequestBindingException {// 從session中拿到imageCodeImageCode codeInSession = (ImageCode) sessionStrategy.getAttribute(request, ValidateCodeController.SESSION_KEY);// 獲取客戶端輸入的code,當(dāng)前請(qǐng)求參數(shù)String codeInRequest = ServletRequestUtils.getStringParameter(request.getRequest(), "imageCode");if(StringUtils.isBlank(codeInRequest)){throw new ValidateCodeException("驗(yàn)證碼不能為空");}if(codeInSession==null){throw new ValidateCodeException("驗(yàn)證碼不存在");}if(codeInSession.isExpired()){throw new ValidateCodeException("驗(yàn)證碼已過(guò)期");}if(!StringUtils.equalsIgnoreCase(codeInSession.getCode(), codeInRequest)){throw new ValidateCodeException("驗(yàn)證碼不匹配");}sessionStrategy.removeAttribute(request, ValidateCodeController.SESSION_KEY);}public AuthenticationFailureHandler getAuthenticationFailureHandler() {return authenticationFailureHandler;}public void setAuthenticationFailureHandler(AuthenticationFailureHandler authenticationFailureHandler) {this.authenticationFailureHandler = authenticationFailureHandler;} } ValidateCodeFilter

?

?

配置:

?

執(zhí)行流程:

?/index.html ->redirect ->/authentication/require(控制器,判斷是.html結(jié)尾)->login.html ->ValidateCodeFilter ->exception ->?VstudyAuthenticationFailHandler ->loginType:JSON

?

login.html中,使用ajax發(fā)送登錄請(qǐng)求 -> 驗(yàn)證碼過(guò)濾器通過(guò) -> UsernamePasswordFilter通過(guò) -> 返回登錄結(jié)果信息

?

3.3 驗(yàn)證碼的接口

  • 為了方便修改驗(yàn)證碼的參數(shù),如寬度、高度、長(zhǎng)度等信息,我們將通過(guò)配置文件的形式配置這些信息。還有驗(yàn)證碼的URL地址。
  • 驗(yàn)證碼攔截的接口可配置,比如為了限制用戶操作頻率,對(duì)用戶操作使用驗(yàn)證碼進(jìn)行限制。驗(yàn)證碼過(guò)濾器可以攔截多個(gè)控制器請(qǐng)求。
  • 驗(yàn)證碼的生成邏輯可以配置

三級(jí)配置:

?

?1)驗(yàn)證碼參數(shù):

  默認(rèn)配置:

/*** 圖形驗(yàn)證碼*/ public class ImageCodeProperties {private int width = 67;private int height = 23;private int len = 4;private int expireIn = 60; //60秒后過(guò)期 //seter getter }

?

?驗(yàn)證碼信息:

/*** 驗(yàn)證碼:包括圖形驗(yàn)證碼、短信驗(yàn)證碼*/ public class ValidateCodeProperties {private ImageCodeProperties image; }

?

?屬性讀取:

@ConfigurationProperties(prefix = "getword.security") public class SecurityProperties {// browser的屬性會(huì)匹配getword.security.browser后面的屬性private BrowserProperties browser = new BrowserProperties();// 驗(yàn)證碼屬性匹配getword.security.code后面的屬性private ValidateCodeProperties code = new ValidateCodeProperties(); }

?

?

?

?

?

?

end

轉(zhuǎn)載于:https://www.cnblogs.com/zhuxiang1633/p/10311320.html

總結(jié)

以上是生活随笔為你收集整理的spring security认证的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。