Spring Security(一):整合JWT
违背的青春
今天写下Spring Security
整合jwt
的一个简单小Demo
,目的是登录后实现返回token
,其实整个过程很简单。
导入依赖
<dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.0</version></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId></dependency>复制代码
首先创建一个JwtUser实现UserDetails
org.springframework.security.core.userdetails.UserDetails
先看一下这个接口的源码,其实很简单
public interface UserDetails extends Serializable { Collection<? extends GrantedAuthority> getAuthorities();
String getPassword();
String getUsername();
boolean isAccountNonExpired();
boolean isAccountNonLocked();
boolean isCredentialsNonExpired();
boolean isEnabled();}复制代码
这个是Spring Security
给我们提供的一个简单的接口,因为我们需要通过SecurityContextHolder
去取得用户凭证等等信息,因为这个比较简单,所以我们实际业务要来加上我们所需要的信息。
public class JwtUser implements UserDetails {
private String username;
private String password;
private Integer state;
private Collection<? extends GrantedAuthority> authorities;
public JwtUser() { }
public JwtUser(String username, String password, Integer state, Collection<? extends GrantedAuthority> authorities) { this.username = username; this.password = password; this.state = state; this.authorities = authorities; }
@Override public String getUsername() { return username; }
@JsonIgnore @Override public String getPassword() { return password; }
@Override public Collection<? extends GrantedAuthority> getAuthorities() { return authorities; }
//账户是否未过期 @JsonIgnore @Override public boolean isAccountNonExpired() { return true; }
//账户是否未被锁 @Override public boolean isAccountNonLocked() { return true; }
@JsonIgnore @Override public boolean isCredentialsNonExpired() { return true; }
//是否启用 @JsonIgnore @Override public boolean isEnabled() { return true; }}复制代码
我这个其实也很简单,只是一些用户名,密码状态和权限的集合这些。
编写一个工具类来生成令牌等…
@Data@ConfigurationProperties(prefix = "jwt")@Componentpublic class JwtTokenUtil implements Serializable {
private String secret;
private Long expiration;
private String header;
/** * 从数据声明生成令牌 * * @param claims 数据声明 * @return 令牌 */ private String generateToken(Map<String, Object> claims) { Date expirationDate = new Date(System.currentTimeMillis() + expiration); return Jwts.builder().setClaims(claims).setExpiration(expirationDate).signWith(SignatureAlgorithm.HS512, secret).compact(); }
/** * 从令牌中获取数据声明 * * @param token 令牌 * @return 数据声明 */ private Claims getClaimsFromToken(String token) { Claims claims; try { claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody(); } catch (Exception e) { claims = null; } return claims; }
/** * 生成令牌 * * @param userDetails 用户 * @return 令牌 */ public String generateToken(UserDetails userDetails) { Map<String, Object> claims = new HashMap<>(2); claims.put("sub", userDetails.getUsername()); claims.put("created", new Date()); return generateToken(claims); }
/** * 从令牌中获取用户名 * * @param token 令牌 * @return 用户名 */ public String getUsernameFromToken(String token) { String username; try { Claims claims = getClaimsFromToken(token); username = claims.getSubject(); } catch (Exception e) { username = null; } return username; }
/** * 判断令牌是否过期 * * @param token 令牌 * @return 是否过期 */ public Boolean isTokenExpired(String token) { try { Claims claims = getClaimsFromToken(token); Date expiration = claims.getExpiration(); return expiration.before(new Date()); } catch (Exception e) { return false; } }
/** * 刷新令牌 * * @param token 原令牌 * @return 新令牌 */ public String refreshToken(String token) { String refreshedToken; try { Claims claims = getClaimsFromToken(token); claims.put("created", new Date()); refreshedToken = generateToken(claims); } catch (Exception e) { refreshedToken = null; } return refreshedToken; }
/** * 验证令牌 * * @param token 令牌 * @param userDetails 用户 * @return 是否有效 */ public Boolean validateToken(String token, UserDetails userDetails) { JwtUser user = (JwtUser) userDetails; String username = getUsernameFromToken(token); return (username.equals(user.getUsername()) && !isTokenExpired(token)); }}复制代码
这个类就是一些生成令牌,验证等等一些操作。具体看注释~
编写一个Filter
@Slf4j@Componentpublic class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
@Autowired private UserDetailsService userDetailsService;
@Autowired private JwtTokenUtil jwtTokenUtil;
@Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { String authHeader = request.getHeader(jwtTokenUtil.getHeader()); if (authHeader != null && StringUtils.isNotEmpty(authHeader)) { String username = jwtTokenUtil.getUsernameFromToken(authHeader); log.info(username); if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) { UserDetails userDetails = this.userDetailsService.loadUserByUsername(username); if (jwtTokenUtil.validateToken(authHeader, userDetails)) { UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); SecurityContextHolder.getContext().setAuthentication(authentication); } } } chain.doFilter(request, response); }}复制代码
这个其实就是用来验证令牌的是否合法,由于今天这个Demo
是一个简单的登录返回token
的过程,所以这个默认不会去执行里面的逻辑。但是以后登陆后的操作就会执行里面的逻辑了。
JwtUserDetailsServiceImpl
JwtUserDetailsServiceImpl
这个实现类是实现了UserDetailsService
,UserDetailsService
是Spring Security
进行身份验证的时候会使用,我们这里就一个加载用户信息的简单方法,就是得到当前登录用户的一些用户名、密码、用户所拥有的角色等等一些信息
@Slf4j@Servicepublic class JwtUserDetailsServiceImpl implements UserDetailsService {
@Autowired private UserMapper userMapper; @Override public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
User user = userMapper.selectByUserName(s); if(user == null){ throw new UsernameNotFoundException(String.format("'%s'.这个用户不存在", s)); } List<SimpleGrantedAuthority> collect = user.getRoles().stream().map(Role::getRolename).map(SimpleGrantedAuthority::new).collect(Collectors.toList()); return new JwtUser(user.getUsername(), user.getPassword(), user.getState(), collect); }}复制代码
编写登录的业务实现类
@Slf4j@Servicepublic class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper;
@Autowired private AuthenticationManager authenticationManager;
@Autowired private UserDetailsService userDetailsService;
@Autowired private JwtTokenUtil jwtTokenUtil;
public User findByUsername(String username) { User user = userMapper.selectByUserName(username); log.info("userserviceimpl"+user); return user; }
public RetResult login(String username, String password) throws AuthenticationException { UsernamePasswordAuthenticationToken upToken = new UsernamePasswordAuthenticationToken(username, password); final Authentication authentication = authenticationManager.authenticate(upToken); SecurityContextHolder.getContext().setAuthentication(authentication); UserDetails userDetails = userDetailsService.loadUserByUsername(username); return new RetResult(RetCode.SUCCESS.getCode(),jwtTokenUtil.generateToken(userDetails)); }}复制代码
从上面可以看到login
方法,会根据用户信息然后返回一个token
给我们。
WebSecurityConfig
这个就是Spring Security
的配置类了
@EnableWebSecurity@EnableGlobalMethodSecurity(prePostEnabled = true)public class WebSecurity extends WebSecurityConfigurerAdapter {
@Autowired private UserDetailsService userDetailsService;
@Autowired private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
@Autowired public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder)throws Exception{ authenticationManagerBuilder.userDetailsService(this.userDetailsService).passwordEncoder(passwordEncoder()); }
@Bean(name = BeanIds.AUTHENTICATION_MANAGER) @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); }
@Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); }
@Override protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and().authorizeRequests() .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() .antMatchers("/auth/**").permitAll() .anyRequest().authenticated() .and().headers().cacheControl();
http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = http.authorizeRequests(); //让Spring security放行所有preflight request registry.requestMatchers(CorsUtils::isPreFlightRequest).permitAll(); }
@Bean public CorsFilter corsFilter() { final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource(); final CorsConfiguration cors = new CorsConfiguration(); cors.setAllowCredentials(true); cors.addAllowedOrigin("*"); cors.addAllowedHeader("*"); cors.addAllowedMethod("*"); urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", cors); return new CorsFilter(urlBasedCorsConfigurationSource); }}复制代码
我们可以在这里设置自定义的拦截规则,注意在Spring Security5.x
中我们要显式注入AuthenticationManager
不然会报错~
@Bean(name = BeanIds.AUTHENTICATION_MANAGER) @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); }复制代码
目前基本的都已经完成了剩下的就是一些entity,controller
的代码了具体可以看我GitHub上的代码。
如果有任何见解或者我有写错的地方可以联系我…我一定改…
下载项目到本地,然后改一下mysql的数据库信息,运行就可以看到返回的token数据了。 欢迎大家关注我的个人公众号~
转载于:https://juejin.im/post/5c30c605518825254e4d10f5
Spring Security(一):整合JWT相关推荐
- Spring Security OAuth2整合JWT
文章目录 1. Spring Security 与 OAuth2 2. Spring Security OAuth2的配置和使用 ①:引入依赖 ②:配置 spring security ③:配置授权服 ...
- JWT实战 Spring Security Oauth2整合JWT 整合SSO单点登录
文章目录 一.JWT 1.1 什么是JWT 1.2 JWT组成 头部(header) 载荷(payload) 签名(signature) 如何应用 1.3 JJWT 快速开始 创建token toke ...
- Spring Security(5) 整合OAuth2
文章目录 一.前言 二.什么是OAuth2? 三.应用场景 四.三部分 五.四种授权模式 1. 授权码模式(authorization code) 2. 简化模式(implicit) 3. 密码模式( ...
- 基于 Spring Security OAuth2和 JWT 构建保护微服务系统
我们希望自己的微服务能够在用户登录之后才可以访问,而单独给每个微服务单独做用户权限模块就显得很弱了,从复用角度来说是需要重构的,从功能角度来说,也是欠缺的.尤其是前后端完全分离之后,我们的用户信息不一 ...
- 《深入理解 Spring Cloud 与微服务构建》第十八章 使用 Spring Security OAuth2 和 JWT 保护微服务系统
<深入理解 Spring Cloud 与微服务构建>第十八章 使用 Spring Security OAuth2 和 JWT 保护微服务系统 文章目录 <深入理解 Spring Cl ...
- Spring Security 4 整合Hibernate 实现持久化登录验证(带源码)
上一篇文章:Spring Security 4 整合Hibernate Bcrypt密码加密(带源码) 原文地址:http://websystique.com/spring-security/spri ...
- 使用Spring Security Oauth2 和 JWT保护微服务--Uaa授权服务器的编写
学习自深入理解微服务 采用Spring Security OAuth2 和 JWT的方式,Uaa服务只需要验证一次,返回JWT.返回的JWT包含了用户的所有信息,包括权限信息 从三个方面讲解: JWT ...
- 用spring security设置用户jwt令牌和设置接口访问权限案例
文章目录 1.配置Swagger 2.spring security配置 3.用户校验逻辑 注册和登录接口 dao层 service层 pojo层 4.加密验证逻辑 5.生成令牌逻辑 身份验证提供者: ...
- Spring Security详细讲解(JWT+SpringSecurity登入案例)
本篇博文目录: 一.SpringSecurity简介 1.SpringSecurity 2.SpringSecurity相关概念 二.认证和授权 1.认证 (1) 使用SpringSecurity进行 ...
- spring boot jwt_springboot整合JWT
springboot整合JWT 一.JWT介绍 JSON Web token简称JWT, 是用于对应用程序上的用户进行身份验证的标记.也就是说, 使用 JWTS 的应用程序不再需要保存有关其用户的 c ...
最新文章
- python解包裹_关于Python中包裹传参和解包裹的理解
- AC日记——中庸之道 codevs 2021
- 汇编语言——基础知识
- 跨平台网络抓包工具-Microsoft Message Analyzer
- wince 德赛西威2413_【图】GPS导航/Wince6.0系统 德赛西威迈腾车载导航改装评测_汽配中国网...
- 基于HT for Web的3D拓扑树的实现
- C# String.Format格式说明
- JDom,jdom解析xml文件
- ufldl学习笔记与编程作业:Multi-Layer Neural Network(多层神经网络+识别手写体编程)...
- 程序员的圣诞节后-零
- CentOS 7防火墙开启路由功能和开放特定端口
- IMPROVING ADVERSARIAL ROBUSTNESS REQUIRES REVISITING MISCLASSIFIED EXAMPLES
- ADO的RECORDSET的RECORDCOUNT属性总是为-1
- 给IBM的黑科技跪了:量子计算机强势来袭!
- 企业信息安全————3、如何建立企业安全框架
- 使用ado访问excel中的数据
- linux练习题十七
- Android Studio 3.5 怎样获取MD5签名
- 设计模式之工厂模式(factory pattern)
- 网盘资源搜索器有哪些?
热门文章
- Radio Button的使用
- Java基础之Switch语句
- zabbix工作流程(自定义添加监控项目)
- 在Makefile中的 .PHONY 是做什么的?
- oracle将213变成123,oracle 转换函数
- java实例变量成员变量_Java的类成员变量、实例变量、类变量,成员方法、实例方法、类方法...
- mysql的数据现实在小程序_使用phpstudy将本地mysql数据显示在微信小程序前端
- python 日历_python中的日历和时间
- HTML 介绍及标签
- 解决Apache配置虚拟主机时出现403错误的问题