Java SpringSecurity+JWT实现登录认证

作者:梦想de星空 时间:2022-12-13 16:44:18 

前言:

学习过我的mall项目的应该知道,mall-admin模块是使用SpringSecurity+JWT来实现登录认证的,而mall-portal模块是使用的SpringSecurity基于Session的默认机制来实现登陆认证的。很多小伙伴都找不到mall-portal的登录接口,最近我把这两个模块的登录认证给统一了,都使用SpringSecurity+JWT的形式实现。主要是通过把登录认证的通用逻辑抽取到了mall-security模块来实现的,下面我们讲讲如何使用mall-security模块来实现登录认证,仅需四步即可。

整合步骤

这里我们以mall-portal改造为例来说说如何实现。

第一步,给需要登录认证的模块添加mall-security依赖:

<dependency>
   <groupId>com.macro.mall</groupId>
   <artifactId>mall-security</artifactId>
</dependency>

第二步,添加MallSecurityConfig配置类,继承mall-security中的SecurityConfig配置,并且配置一个UserDetailsService接口的实现类,用于获取登录用户详情:

/**
* mall-security模块相关配置
* Created by macro on 2019/11/5.
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
publicclass MallSecurityConfig extends SecurityConfig {
   @Autowired
   private UmsMemberService memberService;

@Bean
   public UserDetailsService userDetailsService() {
       //获取登录用户信息
       return username -> memberService.loadUserByUsername(username);
   }
}

第三步,在application.yml中配置下不需要安全保护的资源路径:

secure:
 ignored:
   urls:#安全路径白名单
     -/swagger-ui.html
     -/swagger-resources/**
     -/swagger/**
     -/**/v2/api-docs
     -/**/*.js
     -/**/*.css
     -/**/*.png
     -/**/*.ico
     -/webjars/springfox-swagger-ui/**
     -/druid/**
     -/actuator/**
     -/sso/**
     -/home/**

第四步,在UmsMemberController中实现登录和刷新token的接口:

/**
* 会员登录注册管理Controller
* Created by macro on 2018/8/3.
*/
@Controller
@Api(tags = "UmsMemberController", description = "会员登录注册管理")
@RequestMapping("/sso")
publicclass UmsMemberController {
   @Value("${jwt.tokenHeader}")
   private String tokenHeader;
   @Value("${jwt.tokenHead}")
   private String tokenHead;
   @Autowired
   private UmsMemberService memberService;

@ApiOperation("会员登录")
   @RequestMapping(value = "/login", method = RequestMethod.POST)
   @ResponseBody
   public CommonResult login(@RequestParam String username,
                             @RequestParam String password) {
       String token = memberService.login(username, password);
       if (token == null) {
           return CommonResult.validateFailed("用户名或密码错误");
       }
       Map<String, String> tokenMap = new HashMap<>();
       tokenMap.put("token", token);
       tokenMap.put("tokenHead", tokenHead);
       return CommonResult.success(tokenMap);
   }

@ApiOperation(value = "刷新token")
   @RequestMapping(value = "/refreshToken", method = RequestMethod.GET)
   @ResponseBody
   public CommonResult refreshToken(HttpServletRequest request) {
       String token = request.getHeader(tokenHeader);
       String refreshToken = memberService.refreshToken(token);
       if (refreshToken == null) {
           return CommonResult.failed("token已经过期!");
       }
       Map<String, String> tokenMap = new HashMap<>();
       tokenMap.put("token", refreshToken);
       tokenMap.put("tokenHead", tokenHead);
       return CommonResult.success(tokenMap);
   }
}

实现原理

将SpringSecurity+JWT的代码封装成通用模块后,就可以方便其他需要登录认证的模块来使用,下面我们来看看它是如何实现的,首先我们看下mall-security的目录结构。

目录结构

mall-security
├── component
|    ├── JwtAuthenticationTokenFilter -- JWT登录授权过滤器
|    ├── RestAuthenticationEntryPoint -- 自定义返回结果:未登录或登录过期
|    └── RestfulAccessDeniedHandler -- 自定义返回结果:没有权限访问时
├── config
|    ├── IgnoreUrlsConfig -- 用于配置不需要安全保护的资源路径
|    └── SecurityConfig -- SpringSecurity通用配置
└── util
    └── JwtTokenUtil -- JWT的token处理工具类

做了哪些变化

其实我也就添加了两个类,一个IgnoreUrlsConfig,用于从application.yml中获取不需要安全保护的资源路径。一个SecurityConfig提取了一些SpringSecurity的通用配置。

IgnoreUrlsConfig中的代码:

/**
* 用于配置不需要保护的资源路径
* Created by macro on 2018/11/5.
*/
@Getter
@Setter
@ConfigurationProperties(prefix = "secure.ignored")
publicclass IgnoreUrlsConfig {

private List<String> urls = new ArrayList<>();

}

SecurityConfig中的代码:

/**
* 对SpringSecurity的配置的扩展,支持自定义白名单资源路径和查询用户逻辑
* Created by macro on 2019/11/5.
*/
publicclass SecurityConfig extends WebSecurityConfigurerAdapter {
   @Override
   protected void configure(HttpSecurity httpSecurity) throws Exception {
       ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = httpSecurity
               .authorizeRequests();
       //不需要保护的资源路径允许访问
       for (String url : ignoreUrlsConfig().getUrls()) {
           registry.antMatchers(url).permitAll();
       }
       //允许跨域请求的OPTIONS请求
       registry.antMatchers(HttpMethod.OPTIONS)
               .permitAll();
       // 任何请求需要身份认证
       registry.and()
               .authorizeRequests()
               .anyRequest()
               .authenticated()
               // 关闭跨站请求防护及不使用session
               .and()
               .csrf()
               .disable()
               .sessionManagement()
               .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
               // 自定义权限拒绝处理类
               .and()
               .exceptionHandling()
               .accessDeniedHandler(restfulAccessDeniedHandler())
               .authenticationEntryPoint(restAuthenticationEntryPoint())
               // 自定义权限 * JWT过滤器
               .and()
               .addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
   }

@Override
   protected void configure(AuthenticationManagerBuilder auth) throws Exception {
       auth.userDetailsService(userDetailsService())
               .passwordEncoder(passwordEncoder());
   }
   @Bean
   public PasswordEncoder passwordEncoder() {
       returnnew BCryptPasswordEncoder();
   }
   @Bean
   public JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter() {
       returnnew JwtAuthenticationTokenFilter();
   }
   @Bean
   @Override
   public AuthenticationManager authenticationManagerBean() throws Exception {
       returnsuper.authenticationManagerBean();
   }
   @Bean
   public RestfulAccessDeniedHandler restfulAccessDeniedHandler() {
       returnnew RestfulAccessDeniedHandler();
   }
   @Bean
   public RestAuthenticationEntryPoint restAuthenticationEntryPoint() {
       returnnew RestAuthenticationEntryPoint();
   }
   @Bean
   public IgnoreUrlsConfig ignoreUrlsConfig() {
       returnnew IgnoreUrlsConfig();
   }
   @Bean
   public JwtTokenUtil jwtTokenUtil() {
       returnnew JwtTokenUtil();
   }
}

来源:https://mp.weixin.qq.com/s/4xfdeBHKa_pXabgo41z26g

标签:Java,SpringSecurity,JWT,登录,认证
0
投稿

猜你喜欢

  • c# 通过代码开启或关闭防火墙

    2021-12-11 19:53:20
  • Java反射获取实例的速度对比分析

    2021-06-14 09:22:29
  • MTK Android平台开发流程

    2023-06-23 08:59:11
  • 关于Controller层和Service层的类报错问题及解决方案

    2023-09-28 15:12:23
  • Android自定义View Flyme6的Viewpager指示器

    2022-02-10 19:02:05
  • C#中#define后面只加一个参数的解释

    2022-09-06 07:23:55
  • 关于springboot响应式编程整合webFlux的问题

    2023-12-07 07:25:55
  • mybatis @InsertProvider报错问题及解决

    2023-09-27 15:49:59
  • Android系统工具类详解

    2023-07-12 22:11:57
  • Android开发之滑动数值选择器NumberPicker用法示例

    2022-08-04 07:22:36
  • C#生成单页静态页简单实例

    2022-01-22 20:00:57
  • Java Scanner 类的使用小结

    2023-11-29 00:50:39
  • c# 遍历获取所有文件的示例代码

    2022-11-21 20:01:43
  • Android自定义View图片按Path运动和旋转

    2022-09-15 22:53:11
  • 详解Android中的MVP架构分解和实现

    2022-11-30 08:06:29
  • C# TaskScheduler任务调度器的实现

    2022-09-30 16:54:21
  • Java 实战项目锤炼之医院门诊收费管理系统的实现流程

    2022-08-10 11:35:08
  • Android开发之菜单(menu)用法实例分析

    2022-06-22 23:13:28
  • IntelliJ IDEA中查看当前类的所有继承关系图

    2023-08-06 12:40:19
  • C#/VB.NET中从 PDF 文档中提取所有表格

    2023-04-07 09:11:03
  • asp之家 软件编程 m.aspxhome.com