Spring Security+jwt实现认证

简介: Spring Security+jwt实现认证

创建一个boot项目,引入引入以下依赖

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
</dependency>

自定义查询用户数据

/**
 * 自定义认证服务实现security中的方法
 */
@Service
public class MyUserDetailsServiceImpl implements UserDetailsService {
 
   //实现security接口类userdetails唯一方法
    @Override
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
        //这里执行查数据逻辑
        return new User("123","123",new ArrayList<>());
    }
}

自定义token过滤器

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.filter.OncePerRequestFilter;
 
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
 
@Configuration
public class JwtRequestFilter extends  OncePerRequestFilter {
    @Autowired
    private MyUserDetailsServiceImpl userDetailsService;
 
    @Autowired
    private JwtUtil jwtUtil;
 
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {
 
        final String authorizationHeader = request.getHeader("Authorization");
 
        String username = null;
        String jwt = null;
 
        if (authorizationHeader != null && authorizationHeader.startsWith("jtoken ")) {
            jwt = authorizationHeader.substring(7);
            username = jwtUtil.extractUsername(jwt);
        }
 
 
        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
 
            UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
 
            if (jwtUtil.validateToken(jwt, userDetails)) {
 
                UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
                        userDetails, null, userDetails.getAuthorities());
                usernamePasswordAuthenticationToken
                        .setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
            }
        }
        chain.doFilter(request, response);
    }
 
}

security配置

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private MyUserDetailsServiceImpl myUserDetailsService;
    @Autowired
    private JwtRequestFilter jwtRequestFilter;
 
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(myUserDetailsService);
    }
 
    @Bean
    public PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }
 
    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
 
    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.csrf().disable()
                .authorizeRequests().antMatchers("/login").permitAll().
                anyRequest().authenticated().and().
                exceptionHandling().and().sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
 
    }
}

jwt工具类

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
 
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
 
@Service
public class JwtUtil {
    private String SECRET_KEY = "secret";
 
    public String extractUsername(String token) {
        return extractClaim(token, Claims::getSubject);
    }
 
    public Date extractExpiration(String token) {
        return extractClaim(token, Claims::getExpiration);
    }
 
    public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
        final Claims claims = extractAllClaims(token);
        return claimsResolver.apply(claims);
    }
    private Claims extractAllClaims(String token) {
        return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody();
    }
 
    private Boolean isTokenExpired(String token) {
        return extractExpiration(token).before(new Date());
    }
 
    public String generateToken(UserDetails userDetails) {
        Map<String, Object> claims = new HashMap<>();
        return createToken(claims, userDetails.getUsername());
    }
 
    private String createToken(Map<String, Object> claims, String subject) {
 
        return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis()))
                .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10))
                .signWith(SignatureAlgorithm.HS256, SECRET_KEY).compact();
    }
 
    public Boolean validateToken(String token, UserDetails userDetails) {
        final String username = extractUsername(token);
        return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
    }
}

测试

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
import javax.annotation.Resource;
 
 
@RestController
public class DemoController {
 
    @Resource
    AuthenticationManager authenticationManager;
    @Autowired
    MyUserDetailsServiceImpl userDetailsService;
    @Autowired
    JwtUtil jwtUtil;
 
    @RequestMapping("/login")
    public String login(String userName,String pass){
        Authentication authentication = null;
        try
        {// 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
            authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(userName, pass));
        }
        catch (Exception e)
        {
            if (e instanceof BadCredentialsException)
            {
                return "user.password.not.match";
            }
            else
            {
                return e.getMessage();
            }
        }
        UserDetails user = (UserDetails) authentication.getPrincipal();
        //或者UserDetails userDetails = userDetailsService.loadUserByUsername(userName);
 
        // 生成token
        return jwtUtil.generateToken(user);
    }
 
    @RequestMapping("/hello")
    public String hello(){
        return "hello";
    }
 
}

获取token

携带token访问

 


相关文章
|
4天前
|
JSON 安全 Java
Spring Security 6.x 微信公众平台OAuth2授权实战
上一篇介绍了OAuth2协议的基本原理,以及Spring Security框架中自带的OAuth2客户端GitHub的实现细节,本篇以微信公众号网页授权登录为目的,介绍如何在原框架基础上定制开发OAuth2客户端。
23 4
Spring Security 6.x 微信公众平台OAuth2授权实战
|
8天前
|
存储 安全 Java
Spring Security 6.x OAuth2登录认证源码分析
上一篇介绍了Spring Security框架中身份认证的架构设计,本篇就OAuth2客户端登录认证的实现源码做一些分析。
32 2
Spring Security 6.x OAuth2登录认证源码分析
|
11天前
|
安全 Java 数据安全/隐私保护
Spring Security 6.x 一文快速搞懂配置原理
本文主要对整个Spring Security配置过程做一定的剖析,希望可以对学习Spring Sercurity框架的同学所有帮助。
43 5
Spring Security 6.x 一文快速搞懂配置原理
|
9天前
|
安全 Java API
Spring Security 6.x 图解身份认证的架构设计
【6月更文挑战第1天】本文主要介绍了Spring Security在身份认证方面的架构设计,以及主要业务流程,及核心代码的实现
18 1
Spring Security 6.x 图解身份认证的架构设计
|
9天前
|
安全 前端开发 Java
CSRF 攻击以及如何使用 Spring Security 预防攻击
【6月更文挑战第15天】CSRF 是指跨站请求伪造,是 Cross-site request forgery 的简称,有些地方也简写为 XSRF。
361 1
|
10天前
|
安全 前端开发 Java
Spring Security 6.x 过滤器链SecurityFilterChain是如何工作的
上一篇主要介绍了Spring Secuirty中的过滤器链SecurityFilterChain是如何配置的,那么在配置完成之后,SecurityFilterChain是如何在应用程序中调用各个Filter,从而起到安全防护的作用,本文主要围绕SecurityFilterChain的工作原理做详细的介绍。
49 0
Spring Security 6.x 过滤器链SecurityFilterChain是如何工作的
|
23小时前
|
Java API Spring
Spring Boot整合JWT
Spring Boot整合JWT
|
2天前
|
安全 NoSQL Java
记录spring security执行流程
Spring Security登录授权流程简述: 1. 实现UserDetailsService,从DB加载用户信息。 2. 创建UserDetails实现类,封装用户详情。 3. 配置WebSecurityConfigurerAdapter,用BCryptPasswordEncoder加密。 4. 设定登录接口为匿名访问。 5. 注入AuthenticationManager,用其authenticate方法认证用户
|
6天前
|
存储 安全 Java
spring security原理-学习笔记1-整体概览
spring security原理-学习笔记1-整体概览
|
7天前
|
缓存 安全 Java
【权限管理系统】Spring security(三)---认证过程(原理解析,demo)
【权限管理系统】Spring security(三)---认证过程(原理解析,demo)