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

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

开发者学堂课程【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 操作完成。

相关文章
|
6月前
|
SpringCloudAlibaba Java 网络架构
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(七)Spring Cloud Gateway服务网关
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(七)Spring Cloud Gateway服务网关
283 0
|
6月前
|
SpringCloudAlibaba 负载均衡 Java
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(目录大纲)
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(目录大纲)
167 1
|
6月前
|
SpringCloudAlibaba Java 测试技术
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(六)Hystrix(豪猪哥)的使用
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(六)Hystrix(豪猪哥)的使用
153 1
|
6月前
|
SpringCloudAlibaba 负载均衡 Java
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(三)Eureka服务注册中心
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(三)Eureka服务注册中心
103 1
|
6月前
|
消息中间件 SpringCloudAlibaba Java
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(八)Config服务配置+bus消息总线+stream消息驱动+Sleuth链路追踪
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(八)Config服务配置+bus消息总线+stream消息驱动+Sleuth链路追踪
1009 0
|
6月前
|
SpringCloudAlibaba 负载均衡 Java
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(五)OpenFeign的使用
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(五)OpenFeign的使用
104 0
|
6月前
|
负载均衡 算法 Java
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(四)Ribbon的使用
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(四)Ribbon的使用
139 0
|
1月前
|
NoSQL Java Redis
太惨痛: Redis 分布式锁 5个大坑,又大又深, 如何才能 避开 ?
Redis分布式锁在高并发场景下是重要的技术手段,但其实现过程中常遇到五大深坑:**原子性问题**、**连接耗尽问题**、**锁过期问题**、**锁失效问题**以及**锁分段问题**。这些问题不仅影响系统的稳定性和性能,还可能导致数据不一致。尼恩在实际项目中总结了这些坑,并提供了详细的解决方案,包括使用Lua脚本保证原子性、设置合理的锁过期时间和使用看门狗机制、以及通过锁分段提升性能。这些经验和技巧对面试和实际开发都有很大帮助,值得深入学习和实践。
太惨痛: Redis 分布式锁 5个大坑,又大又深, 如何才能 避开 ?
|
3月前
|
NoSQL Redis
基于Redis的高可用分布式锁——RedLock
这篇文章介绍了基于Redis的高可用分布式锁RedLock的概念、工作流程、获取和释放锁的方法,以及RedLock相比单机锁在高可用性上的优势,同时指出了其在某些特殊场景下的不足,并提到了ZooKeeper作为另一种实现分布式锁的方案。
112 2
基于Redis的高可用分布式锁——RedLock
|
9天前
|
NoSQL Redis
Redis分布式锁如何实现 ?
Redis分布式锁通过SETNX指令实现,确保仅在键不存在时设置值。此机制用于控制多个线程对共享资源的访问,避免并发冲突。然而,实际应用中需解决死锁、锁超时、归一化、可重入及阻塞等问题,以确保系统的稳定性和可靠性。解决方案包括设置锁超时、引入Watch Dog机制、使用ThreadLocal绑定加解锁操作、实现计数器支持可重入锁以及采用自旋锁思想处理阻塞请求。
43 16

热门文章

最新文章