违背的青春

今天写下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这个实现类是实现了UserDetailsServiceUserDetailsServiceSpring 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相关推荐

  1. Spring Security OAuth2整合JWT

    文章目录 1. Spring Security 与 OAuth2 2. Spring Security OAuth2的配置和使用 ①:引入依赖 ②:配置 spring security ③:配置授权服 ...

  2. JWT实战 Spring Security Oauth2整合JWT 整合SSO单点登录

    文章目录 一.JWT 1.1 什么是JWT 1.2 JWT组成 头部(header) 载荷(payload) 签名(signature) 如何应用 1.3 JJWT 快速开始 创建token toke ...

  3. Spring Security(5) 整合OAuth2

    文章目录 一.前言 二.什么是OAuth2? 三.应用场景 四.三部分 五.四种授权模式 1. 授权码模式(authorization code) 2. 简化模式(implicit) 3. 密码模式( ...

  4. 基于 Spring Security OAuth2和 JWT 构建保护微服务系统

    我们希望自己的微服务能够在用户登录之后才可以访问,而单独给每个微服务单独做用户权限模块就显得很弱了,从复用角度来说是需要重构的,从功能角度来说,也是欠缺的.尤其是前后端完全分离之后,我们的用户信息不一 ...

  5. 《深入理解 Spring Cloud 与微服务构建》第十八章 使用 Spring Security OAuth2 和 JWT 保护微服务系统

    <深入理解 Spring Cloud 与微服务构建>第十八章 使用 Spring Security OAuth2 和 JWT 保护微服务系统 文章目录 <深入理解 Spring Cl ...

  6. Spring Security 4 整合Hibernate 实现持久化登录验证(带源码)

    上一篇文章:Spring Security 4 整合Hibernate Bcrypt密码加密(带源码) 原文地址:http://websystique.com/spring-security/spri ...

  7. 使用Spring Security Oauth2 和 JWT保护微服务--Uaa授权服务器的编写

    学习自深入理解微服务 采用Spring Security OAuth2 和 JWT的方式,Uaa服务只需要验证一次,返回JWT.返回的JWT包含了用户的所有信息,包括权限信息 从三个方面讲解: JWT ...

  8. 用spring security设置用户jwt令牌和设置接口访问权限案例

    文章目录 1.配置Swagger 2.spring security配置 3.用户校验逻辑 注册和登录接口 dao层 service层 pojo层 4.加密验证逻辑 5.生成令牌逻辑 身份验证提供者: ...

  9. Spring Security详细讲解(JWT+SpringSecurity登入案例)

    本篇博文目录: 一.SpringSecurity简介 1.SpringSecurity 2.SpringSecurity相关概念 二.认证和授权 1.认证 (1) 使用SpringSecurity进行 ...

  10. spring boot jwt_springboot整合JWT

    springboot整合JWT 一.JWT介绍 JSON Web token简称JWT, 是用于对应用程序上的用户进行身份验证的标记.也就是说, 使用 JWTS 的应用程序不再需要保存有关其用户的 c ...

最新文章

  1. python解包裹_关于Python中包裹传参和解包裹的理解
  2. AC日记——中庸之道 codevs 2021
  3. 汇编语言——基础知识
  4. 跨平台网络抓包工具-Microsoft Message Analyzer
  5. wince 德赛西威2413_【图】GPS导航/Wince6.0系统 德赛西威迈腾车载导航改装评测_汽配中国网...
  6. 基于HT for Web的3D拓扑树的实现
  7. C# String.Format格式说明
  8. JDom,jdom解析xml文件
  9. ufldl学习笔记与编程作业:Multi-Layer Neural Network(多层神经网络+识别手写体编程)...
  10. 程序员的圣诞节后-零
  11. CentOS 7防火墙开启路由功能和开放特定端口
  12. IMPROVING ADVERSARIAL ROBUSTNESS REQUIRES REVISITING MISCLASSIFIED EXAMPLES
  13. ADO的RECORDSET的RECORDCOUNT属性总是为-1
  14. 给IBM的黑科技跪了:量子计算机强势来袭!
  15. 企业信息安全————3、如何建立企业安全框架
  16. 使用ado访问excel中的数据
  17. linux练习题十七
  18. Android Studio 3.5 怎样获取MD5签名
  19. 设计模式之工厂模式(factory pattern)
  20. 网盘资源搜索器有哪些?

热门文章

  1. Radio Button的使用
  2. Java基础之Switch语句
  3. zabbix工作流程(自定义添加监控项目)
  4. 在Makefile中的 .PHONY 是做什么的?
  5. oracle将213变成123,oracle 转换函数
  6. java实例变量成员变量_Java的类成员变量、实例变量、类变量,成员方法、实例方法、类方法...
  7. mysql的数据现实在小程序_使用phpstudy将本地mysql数据显示在微信小程序前端
  8. python 日历_python中的日历和时间
  9. HTML 介绍及标签
  10. 解决Apache配置虚拟主机时出现403错误的问题