广告
返回顶部
首页 > 资讯 > 精选 >Spring Security如何实现HTTP认证
  • 311
分享到

Spring Security如何实现HTTP认证

2023-06-30 18:06:02 311人浏览 安东尼
摘要

今天小编给大家分享一下spring Security如何实现Http认证的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下

今天小编给大家分享一下spring Security如何实现Http认证的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring ioc(控制反转),DI(依赖注入)和aop(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。

前言

除系统内维护的用户名和密码认证技术外,Spring Security还支持HTTP层面的认证,包括HTTP基本认证和HTTP摘要认证

一、HTTP基本认证是什么?

HTTP基本认证是在RFC2616中定义的一种认证模式。

二、HTTP基本认证流程

  • 客户端发起一条没有携带认证信息的请求。

  • 服务器返回一条401 Unauthorized响应, 并在WWW-Authentication首部说明认证形式, 当进行HTTP基本认证时, WWW-Authentication会被设置为Basic realm=“被保护页面”。

  • 客户端收到401 Unauthorized 响应后, 弹出对话框, 询问用户名和密码。 当用户完成后, 客户端将用户名和密码使用冒号拼接并编码为Base64形式, 然后放入请求的Authorization首部发送给服务器

  • 服务器解码得到客户端发来的用户名和密码,并在验证它们是正确的之后,返回客户端请求的报文

Spring Security如何实现HTTP认证

有上面可以看出只需要验证Authentication即可,因此如果不使用浏览器访问HTTP基本认证保护的页面,则自行在请求头中设置Authorization也是可以.

HTTP基本认证是一种无状态的认证方式,与表单认证相比,HTTP基本认证是一种基于HTTP层面的认证方式,无法携带session,即无法实现Remember-ME功能。另外,用户名和密码在传递时仅做一次简单的Base64编码,几乎等同于明文传输,极易出现密码被窃听和重放攻击等安全性问题,在实际系统开发中很少使用这种方式来进行安全验证。 如果有必要,也应使用加密的传输层https来保障安全.

一.Spring Security使用HTTP基本认证

1.创建项目spring-security-http-auth

pom.xml:

<dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-security</artifactId></dependency><dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-WEB</artifactId></dependency>

2.创建配置文件WebSecurityConfig

@EnableWebSecuritypublic class WebSecurityConfig extends WebSecurityConfigurerAdapter {    @Override    protected void configure(HttpSecurity http) throws Exception {        http.authorizeRequests().anyRequest().authenticated().and().httpBasic();    }}

上面的配置最后添加了httpBasic(),使用http基本认证

3.运行项目

访问本地项目,http://localhost:8080

Spring Security如何实现HTTP认证

会弹出登陆框,我们看到调试工具中返回了401无权限。

Spring Security如何实现HTTP认证

我们使用Spring Security提供的默认的用户名和密码登陆。

Spring Security如何实现HTTP认证

登陆成功后,header中就会有Authorization: Basic dXNlcjo0NWU2NzViOC1hZGYwLTQzNzMtYjA2MS02MGE0YzkzZjA2ZGU=

二.Spring Security HTTP基本认证原理

上面我们实现了HTTP基本认证,我们看看其中Spring Security中是如何做到的?
我们使用HTTP基本认证的时候,在配置类中使用httpBasic()进行处理。
httpBasic方法:

public HttpBasicConfigurer<HttpSecurity> httpBasic() throws Exception {        return (HttpBasicConfigurer)this.getOrApply(new HttpBasicConfigurer());    }

上面可以看出,Spring Security进行HTTP基本认证是使用HttpBasicConfigurer配置类进行的。
HttpBasicConfigurer.class:

//构建HttpBasicConfigurerpublic HttpBasicConfigurer() {        this.realmName("Realm");        LinkedHashMap<RequestMatcher, AuthenticationEntryPoint> entryPoints = new LinkedHashMap();        entryPoints.put(X_REQUESTED_WITH, new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED));        DelegatingAuthenticationEntryPoint defaultEntryPoint = new DelegatingAuthenticationEntryPoint(entryPoints);        defaultEntryPoint.setDefaultEntryPoint(this.basicAuthEntryPoint);        this.authenticationEntryPoint = defaultEntryPoint;    }//进行配置public void configure(B http) {//进行认证管理        AuthenticationManager authenticationManager = (AuthenticationManager)http.getSharedObject(AuthenticationManager.class);        //声明basic认证拦截器        BasicAuthenticationFilter basicAuthenticationFilter = new BasicAuthenticationFilter(authenticationManager, this.authenticationEntryPoint);        if (this.authenticationDetailsSource != null) {            basicAuthenticationFilter.setAuthenticationDetailsSource(this.authenticationDetailsSource);        }//注册一个RememberMeServices        RememberMeServices rememberMeServices = (RememberMeServices)http.getSharedObject(RememberMeServices.class);        if (rememberMeServices != null) {//设置rememberMeServices                  basicAuthenticationFilter.setRememberMeServices(rememberMeServices);        }//申明basicAuthenticationFilter过滤器        basicAuthenticationFilter = (BasicAuthenticationFilter)this.postProcess(basicAuthenticationFilter);        http.addFilter(basicAuthenticationFilter);    }

上面声明BasicAuthenticationFilter并添加到拦截器链中
BasicAuthenticationFilter.class:

    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {        try {        //获取token            UsernamePassWordAuthenticationToken authRequest = this.authenticationConverter.convert(request);            //authRequest为空直接放行            if (authRequest == null) {                this.logger.trace("Did not process authentication request since failed to find username and password in Basic Authorization header");                chain.doFilter(request, response);                return;            }//获取用户名            String username = authRequest.getName();            this.logger.trace(LogMessage.fORMat("Found username '%s' in Basic Authorization header", username));            if (this.authenticationIsRequired(username)) {                Authentication authResult = this.authenticationManager.authenticate(authRequest);                //创建上下文                SecurityContext context = SecurityContextHolder.createEmptyContext();                context.setAuthentication(authResult);                //设置响应的上下文                SecurityContextHolder.setContext(context);                if (this.logger.isDebugEnabled()) {                    this.logger.debug(LogMessage.format("Set SecurityContextHolder to %s", authResult));                }                this.rememberMeServices.loginSuccess(request, response, authResult);                this.onSuccessfulAuthentication(request, response, authResult);            }        } catch (AuthenticationException var8) {            SecurityContextHolder.clearContext();            this.logger.debug("Failed to process authentication request", var8);            this.rememberMeServices.loginFail(request, response);            this.onUnsuccessfulAuthentication(request, response, var8);            if (this.ignoreFailure) {                chain.doFilter(request, response);            } else {                this.authenticationEntryPoint.commence(request, response, var8);            }            return;        }        chain.doFilter(request, response);    }

BasicAuthenticationEntryPoint返回进行响应的处理

 public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException { //添加响应响应头        response.addHeader("WWW-Authenticate", "Basic realm=\"" + this.realmName + "\"");        response.sendError(HttpStatus.UNAUTHORIZED.value(), HttpStatus.UNAUTHORIZED.getReasonPhrase());    }

三.HTTP摘要认证是什么?

HTTP摘要认证和HTTP基本认证一样,也是在RFC2616中定义的认证模式,RFC2617专门对这两种认证模式做了规定。与 HTTP 基本认证相比,HTTP 摘要认证使用对通信双方都可知的口令进行校验,且最终的传输数据并非明文形式。

摘要认证是一种协议规定的Web服务器用来同网页浏览器进行认证信息协商的方法。它在密码发出前,先对其应用哈希函数,这相对于HTTP基本认证发送明文而言,更安全。

从技术上讲,摘要认证是使用随机数来阻止进行密码分析的MD5加密哈希函数应用。

HTTP摘要认证中的相关参数:

  • username: 用户名。

  • password: 用户密码。

  • realm: 认证域, 由服务器返回。

  • opaque: 透传字符串, 客户端应原样返回。

  • method: 请求的方法。

  • nonce: 由服务器生成的随机字符串。

  • nc: 即nonce-count, 指请求的次数, 用于计数, 防止重放攻击。 qop被指定时, nc也必须被指定。

  • cnonce: 客户端发给服务器的随机字符串, qop被指定时, cnonce也必须被指定。

  • qop: 保护级别, 客户端根据此参数指定摘要算法。 若取值为auth, 则只进行身份验证; 若取

  • 值为auth-int, 则还需要校验内容完整性。

  • uri: 请求的uri。

  • response:客户端根据算法算出的摘要值。

  • alGorithm:摘要算法, 目前仅支持MD5。

  • entity-body:页面实体,非消息实体,仅在auth-int中支持。

  • 通常服务器携带的数据包括realm、 opaque、 nonce、 qop等字段, 如果客户端需要做出验证回应,就必须按照一定的算法计算得到一些新的数据并一起返回。

四.Spring Security使用HTTP摘要认证流程?

在Spring Security中没有像HTTP基础认证那样,通过httpBasic()方法进行集成HTTP摘要认证,但是Spring Security提供了像BasicAuthenticationEntryPoint一样的DigestAuthenticationEntryPoint.就是我们需要将DigestAuthenticationEntryPoint添加到filter过滤器中去处理。
代码如下:
WebSecurityConfig类:

@EnableWebSecuritypublic class WebSecurityConfig extends WebSecurityConfigurerAdapter {    @Autowired    private DigestAuthenticationEntryPoint digestAuthenticationEntryPoint;    @Autowired    private UserDetailsService userDetailsService;    @Override    protected void configure(HttpSecurity http) throws Exception {        http.authorizeRequests().anyRequest().authenticated().and()                .exceptionHandling()                .authenticationEntryPoint(digestAuthenticationEntryPoint)                .and().addFilter(digestAuthenticationFilter());    }    public DigestAuthenticationFilter digestAuthenticationFilter(){        DigestAuthenticationFilter digestAuthenticationFilter = new DigestAuthenticationFilter();        digestAuthenticationFilter.setUserDetailsService(userDetailsService);        digestAuthenticationFilter.setAuthenticationEntryPoint(digestAuthenticationEntryPoint);        return digestAuthenticationFilter;    }}

申明DigestAuthenticationEntryPointBean:

@Bean    public DigestAuthenticationEntryPoint digestAuthenticationEntryPoint(){        DigestAuthenticationEntryPoint digestAuthenticationEntryPoint = new DigestAuthenticationEntryPoint();        digestAuthenticationEntryPoint.setRealmName("realName");        digestAuthenticationEntryPoint.seTKEy("tony");        return digestAuthenticationEntryPoint;    }@Bean    public DigestAuthenticationEntryPoint digestAuthenticationEntryPoint(){        DigestAuthenticationEntryPoint digestAuthenticationEntryPoint = new DigestAuthenticationEntryPoint();        digestAuthenticationEntryPoint.setRealmName("realm");        digestAuthenticationEntryPoint.setKey("tony");        return digestAuthenticationEntryPoint;    }    @Bean    public UserDetailsService userDetailsService() {        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();        manager.createUser(User.withUsername("tony").password("123456").roles("admin").build());        return manager;    }    @Bean    public PasswordEncoder passwordEncoder() {        return NoOpPasswordEncoder.getInstance();    }

运行项目

访问主页,http://localhost:8080,返回如下页面:

Spring Security如何实现HTTP认证

我们输入用户名和密码登陆。

Spring Security如何实现HTTP认证

当长时间未登录,随机字符串到期了也登陆不上。
默认的过期时间为300s,我们可以通过设置时间。
DigestAuthenticationEntryPoint中realmName和key是必须要设置的。
相关源码

public void afterPropertiesSet() {        Assert.hasLength(this.realmName, "realmName must be specified");        Assert.hasLength(this.key, "key must be specified");    }     public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException { //计算过期时间        long expiryTime = System.currentTimeMillis() + (long)(this.nonceValiditySeconds * 1000);        //计算签名值        String signatureValue = DigestAuthUtils.md5Hex(expiryTime + ":" + this.key);        //随机字符串        String nonceValue = expiryTime + ":" + signatureValue;        //随机字符串base64        String nonceValueBase64 = new String(Base64.getEncoder().encode(nonceValue.getBytes()));        String authenticateHeader = "Digest realm=\"" + this.realmName + "\", qop=\"auth\", nonce=\"" + nonceValueBase64 + "\"";        if (authException instanceof NonceExpiredException) {            authenticateHeader = authenticateHeader + ", stale=\"true\"";        }        logger.debug(LogMessage.format("WWW-Authenticate header sent to user agent: %s", authenticateHeader));        response.addHeader("WWW-Authenticate", authenticateHeader);        response.sendError(HttpStatus.UNAUTHORIZED.value(), HttpStatus.UNAUTHORIZED.getReasonPhrase());    }

进行处理的时候使用DigestAuthenticationFilter进行处理

public void afterPropertiesSet() {//必须设置userDetailsService        Assert.notNull(this.userDetailsService, "A UserDetailsService is required");        //必须设置authenticationEntryPoint        Assert.notNull(this.authenticationEntryPoint, "A DigestAuthenticationEntryPoint is required");    }private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {        String header = request.getHeader("Authorization");        if (header != null && header.startsWith("Digest ")) {            logger.debug(LogMessage.format("Digest Authorization header received from user agent: %s", header));            DigestAuthenticationFilter.DigestData digestAuth = new DigestAuthenticationFilter.DigestData(header);            try {//验证并且解密                digestAuth.validateAndDecode(this.authenticationEntryPoint.getKey(), this.authenticationEntryPoint.getRealmName());            } catch (BadCredentialsException var11) {                this.fail(request, response, var11);                return;            }            //缓存            boolean cacheWasUsed = true;            //缓存用户数据            UserDetails user = this.userCache.getUserFromCache(digestAuth.getUsername());            String serverDigestMd5;            try {                if (user == null) {                    cacheWasUsed = false;                    user = this.userDetailsService.loadUserByUsername(digestAuth.getUsername());                    if (user == null) {                        throw new AuthenticationServiceException("AuthenticationDao returned null, which is an interface contract violation");                    }                    this.userCache.putUserInCache(user);                }//服务器md5摘要                serverDigestMd5 = digestAuth.calculateServerDigest(user.getPassword(), request.getMethod());                if (!serverDigestMd5.equals(digestAuth.getResponse()) && cacheWasUsed) {                    logger.debug("Digest comparison failure; trying to refresh user from DAO in case password had changed");                    user = this.userDetailsService.loadUserByUsername(digestAuth.getUsername());                    this.userCache.putUserInCache(user);                    serverDigestMd5 = digestAuth.calculateServerDigest(user.getPassword(), request.getMethod());                }            } catch (UsernameNotFoundException var12) {                String message = this.messages.getMessage("DigestAuthenticationFilter.usernameNotFound", new Object[]{digestAuth.getUsername()}, "Username {0} not found");                this.fail(request, response, new BadCredentialsException(message));                return;            }            String message;            if (!serverDigestMd5.equals(digestAuth.getResponse())) {                logger.debug(LogMessage.format("Expected response: '%s' but received: '%s'; is AuthenticationDao returning clear text passwords?", serverDigestMd5, digestAuth.getResponse()));                message = this.messages.getMessage("DigestAuthenticationFilter.incorrectResponse", "Incorrect response");                this.fail(request, response, new BadCredentialsException(message));            } else if (digestAuth.isNonceExpired()) {                message = this.messages.getMessage("DigestAuthenticationFilter.nonceExpired", "Nonce has expired/timed out");                this.fail(request, response, new NonceExpiredException(message));            } else {                logger.debug(LogMessage.format("Authentication success for user: '%s' with response: '%s'", digestAuth.getUsername(), digestAuth.getResponse()));                Authentication authentication = this.createSuccessfulAuthentication(request, user);                SecurityContext context = SecurityContextHolder.createEmptyContext();                context.setAuthentication(authentication);                SecurityContextHolder.setContext(context);                chain.doFilter(request, response);            }        } else {            chain.doFilter(request, response);        }    }

DigestData为摘要数据:

 private class DigestData {//用户名    private final String username;    //认证域    private final String realm;    //随机字符串    private final String nonce;    private final String uri;    private final String response;    //保护级别    private final String qop;    //即nonce-count, 指请求的次数, 用于计数, 防止重放攻击    private final String nc;    private final String cnonce;    private final String section212response;    private long nonceExpiryTime;    DigestData(String header) {        this.section212response = header.substring(7);        String[] headerEntries = DigestAuthUtils.splitIgnoringQuotes(this.section212response, ',');        Map<String, String> headerMap = DigestAuthUtils.splitEachArrayElementAndCreateMap(headerEntries, "=", "\"");        this.username = (String)headerMap.get("username");        this.realm = (String)headerMap.get("realm");        this.nonce = (String)headerMap.get("nonce");        this.uri = (String)headerMap.get("uri");        this.response = (String)headerMap.get("response");        this.qop = (String)headerMap.get("qop");        this.nc = (String)headerMap.get("nc");        this.cnonce = (String)headerMap.get("cnonce");        DigestAuthenticationFilter.logger.debug(LogMessage.format("Extracted username: '%s'; realm: '%s'; nonce: '%s'; uri: '%s'; response: '%s'", new Object[]{this.username, this.realm, this.nonce, this.uri, this.response}));    }   //验证和解密    void validateAndDecode(String entryPointKey, String expectedRealm) throws BadCredentialsException {        if (this.username != null && this.realm != null && this.nonce != null && this.uri != null && this.response != null) {            if ("auth".equals(this.qop) && (this.nc == null || this.cnonce == null)) {                DigestAuthenticationFilter.logger.debug(LogMessage.format("extracted nc: '%s'; cnonce: '%s'", this.nc, this.cnonce));                throw new BadCredentialsException(DigestAuthenticationFilter.this.messages.getMessage("DigestAuthenticationFilter.missingAuth", new Object[]{this.section212response}, "Missing mandatory digest value; received header {0}"));            } else if (!expectedRealm.equals(this.realm)) {                throw new BadCredentialsException(DigestAuthenticationFilter.this.messages.getMessage("DigestAuthenticationFilter.incorrectRealm", new Object[]{this.realm, expectedRealm}, "Response realm name '{0}' does not match system realm name of '{1}'"));            } else {                byte[] nonceBytes;                try {                    nonceBytes = Base64.getDecoder().decode(this.nonce.getBytes());                } catch (IllegalArgumentException var8) {                    throw new BadCredentialsException(DigestAuthenticationFilter.this.messages.getMessage("DigestAuthenticationFilter.nonceEncoding", new Object[]{this.nonce}, "Nonce is not encoded in Base64; received nonce {0}"));                }                String nonceAsPlainText = new String(nonceBytes);                String[] nonceTokens = StringUtils.delimitedListToStringArray(nonceAsPlainText, ":");                if (nonceTokens.length != 2) {                    throw new BadCredentialsException(DigestAuthenticationFilter.this.messages.getMessage("DigestAuthenticationFilter.nonceNotTwoTokens", new Object[]{nonceAsPlainText}, "Nonce should have yielded two tokens but was {0}"));                } else {                    try {                        this.nonceExpiryTime = new Long(nonceTokens[0]);                    } catch (NumberFormatException var7) {                        throw new BadCredentialsException(DigestAuthenticationFilter.this.messages.getMessage("DigestAuthenticationFilter.nonceNotNumeric", new Object[]{nonceAsPlainText}, "Nonce token should have yielded a numeric first token, but was {0}"));                    }                    String expectedNonceSignature = DigestAuthUtils.md5Hex(this.nonceExpiryTime + ":" + entryPointKey);                    if (!expectedNonceSignature.equals(nonceTokens[1])) {                        throw new BadCredentialsException(DigestAuthenticationFilter.this.messages.getMessage("DigestAuthenticationFilter.nonceCompromised", new Object[]{nonceAsPlainText}, "Nonce token compromised {0}"));                    }                }            }        } else {            throw new BadCredentialsException(DigestAuthenticationFilter.this.messages.getMessage("DigestAuthenticationFilter.missingMandatory", new Object[]{this.section212response}, "Missing mandatory digest value; received header {0}"));        }    }//计算服务摘要    String calculateServerDigest(String password, String httpMethod) {    //生产摘要        return DigestAuthUtils.generateDigest(DigestAuthenticationFilter.this.passwordAlreadyEncoded, this.username, this.realm, password, httpMethod, this.uri, this.qop, this.nonce, this.nc, this.cnonce);    }//判断随机数是否到期    boolean isNonceExpired() {        long now = System.currentTimeMillis();        return this.nonceExpiryTime < now;    }    String getUsername() {        return this.username;    }    String getResponse() {        return this.response;    }}

以上就是“Spring Security如何实现HTTP认证”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注编程网精选频道。

--结束END--

本文标题: Spring Security如何实现HTTP认证

本文链接: https://www.lsjlt.com/news/330672.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Spring Security实现HTTP认证
    目录前言一、HTTP基本认证是什么?二、HTTP基本认证流程一.Spring Security使用HTTP基本认证1.创建项目spring-security-http-auth2.创...
    99+
    2022-11-13
  • Spring Security如何实现HTTP认证
    今天小编给大家分享一下Spring Security如何实现HTTP认证的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下...
    99+
    2023-06-30
  • Spring Boot中如何实现HTTP认证
    这篇文章将为大家详细讲解有关Spring Boot中如何实现HTTP认证,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。HttpBasic 认证有一定的局限性与安全隐患,因此在实际项目中使用并...
    99+
    2023-06-03
  • Spring Security认证器实现过程详解
    目录拦截请求验证过程返回完整的Authentication收尾工作结论一些权限框架一般都包含认证器和决策器,前者处理登陆验证,后者处理访问资源的控制 Spring Security的...
    99+
    2022-11-13
  • spring security 自定义Provider 如何实现多种认证
    目录security内部认证流程是这样的1、 Controller2、spring security3、调用匹配的provider内部认证逻辑4、UserDetailsService...
    99+
    2022-11-12
  • SpringBoot集成Spring security JWT实现接口权限认证
    1、添加依赖 <dependency> <groupId>org.springframework.boot</groupId> ...
    99+
    2022-11-12
  • Springboot WebFlux集成Spring Security实现JWT认证的示例
    目录1 简介 2 项目整合 2.1 JWT工具类 2.2 JWT的过滤器 2.3 Security的配置 2.4 获取JWT的Controller 3 总结 1 简介 在之前的文章...
    99+
    2022-11-12
  • Spring Security(新版本)实现权限认证与授权
    学习新版SpringSecurity详细配置 一、Spring Security介绍1、Spring Security简介2、历史3、同款产品对比3.1、Spring Security3.2、...
    99+
    2023-09-14
    spring java 后端
  • Spring Security如何实现登录验证
    这篇文章主要讲解了“Spring Security如何实现登录验证”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Spring Security如何实现登录验证”吧!一、理...
    99+
    2023-06-26
  • SpringBoot security安全认证登录如何实现
    本文小编为大家详细介绍“SpringBoot security安全认证登录如何实现”,内容详细,步骤清晰,细节处理妥当,希望这篇“SpringBoot security安全认证登录如何实现”文章能帮助大家解决疑惑,下面跟...
    99+
    2023-07-05
  • Spring Security自定义认证逻辑实例详解
    目录前言分析问题自定义 Authentication自定义 Filter自定义 Provider自定义认证成功/失败后的 Handler配置自定义认证的逻辑测试总结前言 这篇文章的内...
    99+
    2022-11-13
  • Java开发之spring security实现基于MongoDB的认证功能
    本文实例讲述了Java开发之spring security实现基于MongoDB的认证功能。分享给大家供大家参考,具体如下:spring security对基于数据库的认证支持仅限于JDBC,而很多项目并非使用JDBC,比如Nosql数据库...
    99+
    2023-05-30
    java spring security
  • 【全网最细致】SpringBoot整合Spring Security + JWT实现用户认证
    【全网最细致】SpringBoot整合Spring Security + JWT实现用户认证   登录和用户认证是一个网站最基本的功能,在这篇博客里,将介绍如何用SpringBoot整合Spring Security + JWT实现登录及用...
    99+
    2023-08-18
    spring boot java 后端 vue.js 开发语言
  • Spring Security如何使用数据库登录认证授权
    本篇文章给大家分享的是有关Spring Security如何使用数据库登录认证授权,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。一、搭建项目环境1、创建 RBAC五张...
    99+
    2023-06-22
  • Spring Boot+Shiro实现一个Http请求的Basic认证
    目录前言实践部分测试部分总结前言 今天跟小伙伴们分享一个实战内容,使用Spring Boot+Shiro实现一个简单的Http认证。 场景是这样的,我们平时的工作中可能会对外提供一...
    99+
    2022-11-12
  • Spring Security短信验证码实现详解
    目录需求实现步骤获取短信验证码短信验证码校验过滤器短信验证码登录认证配置类进行综合组装需求 输入手机号码,点击获取按钮,服务端接受请求发送短信 用户输入验证码点击...
    99+
    2022-11-12
  • Spring Security基于自定义的认证提供器实现图形验证码流程解析
    目录前言一. 认证提供器简介1. 认证提供器AuthenticationProver2. WebAuthenticationDetails类介绍二. 实现图形验证码1. 添加依赖包2...
    99+
    2022-11-12
  • 如何实现Spring+ Spring cloud + SSO单点登录应用认证
    今天就跟大家聊聊有关如何实现Spring+ Spring cloud + SSO单点登录应用认证,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。不同系统的无缝隙集成,统一的sso单点登...
    99+
    2023-06-05
  • Springboot+Spring Security实现前后端分离登录认证及权限控制的示例代码
    目录前言本文主要的功能 一、准备工作1、统一错误码枚举2、统一json返回体3、返回体构造工具4、pom5、配置文件二、数据库表设计初始化表数据语句三、Spring Sec...
    99+
    2022-11-12
  • Spring Boot怎么实现通用Auth认证
    这篇文章主要介绍“Spring Boot怎么实现通用Auth认证”,在日常操作中,相信很多人在Spring Boot怎么实现通用Auth认证问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”S...
    99+
    2023-06-29
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作