分布式整合之重写认证的过滤器|学习笔记

简介: 快速学习分布式整合之重写认证的过滤器

开发者学堂课程【Spring Security知识精讲与实战演示(三)分布式整合之重写认证的过滤器】学习笔记与课程紧密联系,让用户快速学习知识

课程地址https://developer.aliyun.com/learning/course/732/detail/13071


分布式整合之重写认证的过滤器

分布式整合之重写认证的过滤器

之前编写了RoleMapper和UserMapper,但是忘记在

AuthServerApplication.java 代码中加上 @MapperScan("com itheima. mapper"),这样之后就可以自动扫描并生成代理对象。

import com itheima.config.RsaKeyProperties;

import org.mybatis.spr ing. annotation. MapperScan;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.

SpringBootApplication;

Import org.springframework.boot.context.proper

ties.EnableConfigurationProperties;

@SpringBootApplication

@MapperScan("com itheima. mapper")

@EnableConfigurationProperties(RsaKeyProperties.class)

public class AuthServerApplication {

public static void main(String[] args){

SpringApplication.run(AuthServerApplication.class, args);

}

}

另外,在RsaKeyProperties.java中不需要

@ConfigurationProperties("rsa.key")加入@Configuratio,因为声明了配置类就意味着当前对象不放入aoc容器中,而我们需要将当前对象放入容器中,故不需要这个注解。

import javax. annotation. PostConstruct;

import java. security. PrivateKey;

import java. security. PublicKey;

@ConfigurationProperties("rsa.key") .

public class RsaKeyProperties {

private Str ing pubKeyFile;

private String pr KeyFile;

private PublicKey publicKey;

private PrivateKey privateKey;

接下来,重新定义认证方法:

创建一个新的过滤器,名称为 filter.JwtTokenFilter 或者 filter.JwtLoginFilter,如下图。

image.png

package com. itheima.filter ;

public class JwtLoginFilter{

}

JwtLoginFilter 里,需要对默认的 UsernamePasswordluthenticationFilter 进行继承,继承的目的是为了重写其中的两个方法。

package com. itheima.filter ;

import org.springframework. security.web. authentic

ation. UsernamePasswordluthenticationFilter;

public class JwtLoginFilter extends UsernamePassword

AuthenticationFilter{

}

第一是认证逻辑,内容如下

public Authentication attemptAuthentication(HttpS

ervletRequest request,HttpServletResponse response) throws

if (this.postOnly && !request.getMethod().equals("PO

ST")) {

throw new AuthenticationServiceException("Authentic

ation method not supported: " + request.getMethod

} else {

String username = this.obtainUsername (request);

String password = this.obtainPassword(reqhest);

if (username == null){

username = “”;

}

if (password == null) {

password = "";

}

username = username.trim() ;

UsernamePassworduthenticationToken authRequest = new UsernamePasswordAuthenticationToken(usern

amethis.setDetails(request,authRequest);

return this.getAuthenticationManager (). Authenticate

(authRequest);

}

}

将上述内容粘贴进JwtLoginFilte,只需要留return一句:

Import org.springframework.security.core.Authentic

ationException;

import org.springframework.security.web. authen

tication. UsernamePassworduthenticationFilter;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse ;

public class JwtLoginFilter extends UsernamePasswordAuthenticationFilter {

public Authentication attempt;huthentication(HttpS

ervletRequest request,HttpServrletResponse response) throws Authentican

return this.getAuthenticationManager(). Authenticate

(authRequest);

}

}

authRequestUsernamePassvordauthenticationI

Token authRequest = new UsernamePassword

Quthentication Token(usernamepassword)

之后将这个token粘进JwtLoginFilte

public Authentication attempt;huthentication(HttpS

ervletRequest request,HttpServrletResponse response) throws Authentican

UsernamePassvordauthenticationIToken authRequest = new UsernamePasswordquthentication

Token(username,password)

return this.getAuthenticationManager(). Authenticate

(authRequest);

}

}

这个token里需要传入 username和password,在这里可以直接从请求体中解析出来;getAuthenticationManager()对象是要 AuthenticationManager

public class JwtLoginFilter extends UsernamePasswordAuthenticationFilter {

private AuthenticationManager authenticationManager;

注:以上代码是没有值的,需要生成一个带参数的构造方法。

private RsaKeyProperties prop;

public JwtLoginFilter(AuthenticationManager authenticationManager,RsaKeyProperties prop){

this.authenticationManager = authenticationManager ;

this.prop = prop;

}

public Authentication attempt;huthentication(HttpS

ervletRequest request,HttpServrletResponse response) throws AuthenticanException {

注:获取username和password,这里是有异常的,要进行try/catch Block操作。

Try{

SysUser sysUser = new ObjectMapper().readValue(request.getInputStream(),SysUser.class);

UsernamePassvordauthenticationIToken authRequest = new UsernamePasswordquthenticationToken(sysUser.getUsername(), sysUser.getPassword())

return this.getAuthenticationManager(). Authenticate

(authRequest);

}catch (Exception e) {

throw new RuntimeException(e);

}

}

得到用户对象之后,username和password改为sysUser.getUsername(), sysUser.getPassword(),且这两个数据都是用户输入过来的

接下来可以输入throw new RuntimeException(e)将异常抛出去

注意,在这个代码中是异步请求并未跳转任何界面,如果没有成功,要提示用户,直接抛异常用户是看不见的,可以进行以下操作提示用户。

return this.getAuthenticationManager(). Authenticate

(authRequest);

}catch (Exception e) {

try {

//登陆成功时,返回JSON格式进行提示

response.setContentType("application/json; charset=

utf-8"");

response. setStatus (HttpServletResponse.SC_UNAUT

HORIZED);

PrintWriter out = response.getWriter() ;

Map resultMap = new HashMap();

resultMap.put("code",HttpServletResponse.SC_UNAU

THORIZED);

resultMap. put("msg","用户名或密码错误!")

out.write(new 0bjectMapper ().writeValueAsString (resultMapp )

out.flush() ;

out.close();

throw new RuntimeException(e);

} catch (Exception outEx)【

outEx.printStackTrace() ;

}

throw new RuntimeException(e);

}

}

到此,上面的认证逻辑完成,其会根据后续的认证操作进行判断,用户名或密码正确则认证通过,认证失败则显示“用户名或密码错误”;如果认证成功,会继续执行一段代码,这段代码写在

UsernamePasswordAuthenticationFilter过滤器的副类中:

Protected voids uccessfulkuthentication(HttpServlet

Request request,HittpServletResponse response,FilterChain chain, Authentican Exception();

if (this. logger.isDebugEnabled()){

this. logger. debug (o:"Authentication success.Upda

ting SecurityContextHolder to contain:" + authResult);

}SecurityContextHolder.getContext(.setAuthentication(authResult);

this.rememberMeServices.loginSuccess(request,response,authResult);

if (this.eventPublisher != null){

this.eventPublisher. publishEvent(new Interactive

AuthenticationSuccessEvent(authResult,this.getClass()>);

this. successHandler. onAuthenticationSuccess(request,response,authResult);

}

将上述内容中

Protected voids uccessfulkuthentication(HttpServlet

Request request,HittpServletResponse response,FilterChain chain, Authentication authResult)throws I0Exception,ServletException

的粘进JwtLoginFilte,之后这下面要生成token:

Protected voids uccessfulkuthentication(HttpServlet

Request request,HittpServletResponse response,FilterChain chain, Authentican Exception();

String token = JwtUtils.generateTokenExpire InMinutes(userT prop.getPrivateKey(),expire:24* 60) ;

}

}

注:generateTokenExpire InMinutes 里的Object usqr Info,代表自己定义的用户对象;PrivateKey privateKey,代表加密需要使用的私钥;int expire),代表过期时间

现在这里的user对象是不存在的,下面创建user对象:

Protected voids uccessfulkuthentication(HttpServlet

Request request,HittpServletResponse response,FilterChain chain, Authentican Exception();

SysUser user = new SysUser();

user.setUsername(authResult.getName()) ;

user.setRoles((List<SysRole>) authResult.getAuthorities();

String token = JwtUtils.generateTokenExpire InMinutes(userT prop.getPrivateKey(),expire:24* 60) ;

}

}

至此,token完成,需要将token写回给请求者,可以将其写回到请求头里面,里面的名称可以随便取,但一般都为"Authorization","Bearer" + token

String token = JwtUtils.generateTokenExpire InMinutes(userT prop.getPrivateKey(),expire:24* 60) ;

res.addHeader("Authorization","Bearer" + token);

try {

//登陆成功时,返回JSON格式进行提示

response.setContentType("application/json; charset=

utf-8"");

response. setStatus (HttpServletResponse.SC_OK);

PrintWriter out = response.getWriter() ;

Map resultMap = new HashMap();

resultMap.put("code",HttpServletResponse.SC_OK);

resultMap. put("msg","证通过!");

out.write(new 0bjectMapper ().writeValueAsString (resultMapp )

out.flush() ;

out.close();

throw new RuntimeException(e);

} catch (Exception outEx)【

outEx.printStackTrace() ;

}

}

认证成功之后回写 token 操作完成。

相关文章
|
8月前
|
SpringCloudAlibaba Java 网络架构
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(七)Spring Cloud Gateway服务网关
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(七)Spring Cloud Gateway服务网关
316 0
|
8月前
|
SpringCloudAlibaba 负载均衡 Java
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(目录大纲)
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(目录大纲)
197 1
|
8月前
|
SpringCloudAlibaba Java 测试技术
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(六)Hystrix(豪猪哥)的使用
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(六)Hystrix(豪猪哥)的使用
167 1
|
8月前
|
SpringCloudAlibaba 负载均衡 Java
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(三)Eureka服务注册中心
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(三)Eureka服务注册中心
115 1
|
8月前
|
消息中间件 SpringCloudAlibaba Java
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(八)Config服务配置+bus消息总线+stream消息驱动+Sleuth链路追踪
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(八)Config服务配置+bus消息总线+stream消息驱动+Sleuth链路追踪
1046 0
|
8月前
|
SpringCloudAlibaba 负载均衡 Java
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(五)OpenFeign的使用
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(五)OpenFeign的使用
111 0
|
8月前
|
负载均衡 算法 Java
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(四)Ribbon的使用
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(四)Ribbon的使用
165 0
|
3月前
|
NoSQL Java Redis
太惨痛: Redis 分布式锁 5个大坑,又大又深, 如何才能 避开 ?
Redis分布式锁在高并发场景下是重要的技术手段,但其实现过程中常遇到五大深坑:**原子性问题**、**连接耗尽问题**、**锁过期问题**、**锁失效问题**以及**锁分段问题**。这些问题不仅影响系统的稳定性和性能,还可能导致数据不一致。尼恩在实际项目中总结了这些坑,并提供了详细的解决方案,包括使用Lua脚本保证原子性、设置合理的锁过期时间和使用看门狗机制、以及通过锁分段提升性能。这些经验和技巧对面试和实际开发都有很大帮助,值得深入学习和实践。
太惨痛: Redis 分布式锁 5个大坑,又大又深, 如何才能 避开 ?
|
1月前
|
存储 NoSQL Java
使用lock4j-redis-template-spring-boot-starter实现redis分布式锁
通过使用 `lock4j-redis-template-spring-boot-starter`,我们可以轻松实现 Redis 分布式锁,从而解决分布式系统中多个实例并发访问共享资源的问题。合理配置和使用分布式锁,可以有效提高系统的稳定性和数据的一致性。希望本文对你在实际项目中使用 Redis 分布式锁有所帮助。
104 5
|
2月前
|
NoSQL Java 数据处理
基于Redis海量数据场景分布式ID架构实践
【11月更文挑战第30天】在现代分布式系统中,生成全局唯一的ID是一个常见且重要的需求。在微服务架构中,各个服务可能需要生成唯一标识符,如用户ID、订单ID等。传统的自增ID已经无法满足在集群环境下保持唯一性的要求,而分布式ID解决方案能够确保即使在多个实例间也能生成全局唯一的标识符。本文将深入探讨如何利用Redis实现分布式ID生成,并通过Java语言展示多个示例,同时分析每个实践方案的优缺点。
70 8