Springboot项目整合JWT

一、JWT简介

  1. JWT: JSON Web Token(JSON Web令牌)

JWT是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。

  1. JWT认证流程:

  1. JWT优点:

  • 简洁(Compact):可以通过URL,POST参数或者在HTTP header发送,数据量小,传输速度也很快;

  • 自包含(Self-contained):负载中包含了所有用户所需要的信息,避免了多次查询数据库;

  • Token是以JSON加密的形式保存在客户端,所以JWT是跨语言的,原则上任何web形式都支持。

  • 不需要在服务端保存会话信息,特别适用于分布式微服务。

  1. JWT结构:

JWT令牌token,是一个String字符串,由3部分组成,中间用点隔开

令牌组成:标头(Header).有效载荷(Payload).签名(Signature)

token格式:head.payload.singurater 如:

eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIxIiwic3ViIjoie1wiZWRpdGVkXCI6MTY3OTIyODMwNjAwMCxcImVkaXRvclwiOlwiXCIsXCJoZWFkUG9ydHJhaXRcIjpcImh0dHBzOi8vemhpaHVpcGFpYmFuLTEzMTcwNTExMjkuY29zLmFwLW5hbmppbmcubXlxY2xvdWQuY29tL2hlYWRQb3J0cmFpdC8yNTM1MTY3OTIyOTU0MjI0MC5qcGdcIixcImlkXCI6MjIsXCJqb2JOdW1iZXJcIjpcIjIwMjA0MjI4MDEzXCIsXCJtYWlsYm94XCI6XCIyMzIyNjU2NDMwQHFxLmNvbVwiLFwibmFtZVwiOlwi6ams5pmT5aSpXCIsXCJwYXNzd29yZFwiOlwiNjNlZTQ1MTkzOWVkNTgwZWYzYzRiNmYwMTA5ZDFmZDBcIixcInBob25lXCI6XCIxODc3MjYzODE2MFwiLFwicm9sZWlkXCI6MTAsXCJzZXhcIjpcIjBcIixcInVzZXJuYW1lXCI6XCIxODc3MjYzODE2MFwifSIsImlzcyI6IkZhbmppbmd4dWFuIiwiaWF0IjoxNjc5MjMwOTAyLCJleHAiOjE2NzkyMzA5NjJ9.j0WFGkEACHpTnvEc9EiTEJCQKJ20oIptfrL_kMPz4kU

二、Springboot项目整合JWT验证+拦截器

(参考项目:intelligent_scheduling)

  1. 在pom文件中添加JWT的依赖

 <!--JWT -->
<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.2.0</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.7.0</version>
</dependency>
  1. 在model层创建JWT的实体类CheckResult

package cn.com.fanjingxuan.model;

import io.jsonwebtoken.Claims;

/**
  * @className: CheckResult.java
  * @methodName: CheckResult
  * @effect: jwt验证信息实体封装类
  * @author: JingxuanFan
  * @date: 2023/3/19 15:16
  **/
public class CheckResult {

    //
    private int errCode;
    //
    private boolean success;
    //
    private Claims claims;

    public int getErrCode(){ return errCode;}
    public void setErrCode(int errCode){ this.errCode = errCode;}
    public boolean isSuccess(){ return success;}
    public void setSuccess(boolean success){ this.success = success;}
    public Claims getClaims(){ return claims;}
    public void setClaims(Claims claims){ this.claims = claims;}
}
  1. 在constant层中创建JWT的系统级静态变量SystemConstant

package cn.com.fanjingxuan.constant;

/**
 *系统级静态变量
 * @author JingxuanFan
 * @date: 2023/3/19 15:13
 */
public class SystemConstant {

    /**
     *token
     */
    public static final int JWT_ERRCODE_NULL = 4000; //Token不存在
    public static final int JWT_ERRCODE_EXPIRE = 4001; //Token过期
    public static final int JWT_ERRCODE_FAIL = 4002; //验证不通过
    /**
     * JWT
     */
    public static final String JWT_SECERT = "8677df7fc3a34e26a61c034d5ec8245d"; //密匙
    public static final long JWT_TTL = 30 * 60 * 1000; //token有效时间为半小时
}
  1. 在util层创建JWT的工具包JwtUtil

package cn.com.fanjingxuan.util;

import cn.com.fanjingxuan.constant.SystemConstant;
import cn.com.fanjingxuan.model.CheckResult;
import com.alibaba.fastjson.JSON;
import io.jsonwebtoken.*;
import org.bouncycastle.util.encoders.Base64;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Date;

/**
  * @className: JwtUtil.java
  * @methodName: JwtUtil
  * @effect: jwt加密和解密的工具类
  * @author: JingxuanFan
  * @date: 2023/3/19 14:52
  **/
public class JwtUtil {
    /**
     * 签发JWT
     * @param id
     * @param subject 可以是JSON数据 尽可能少
     * @param ttlMillis
     * @return
     */
    public static String createJWT(String id, String subject, long ttlMillis) {
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        SecretKey secretKey = generalKey();
        JwtBuilder builder = Jwts.builder()
                .setId(id)
                .setSubject(subject)   // 主题
                .setIssuer("Java1234")     // 签发者
                .setIssuedAt(now)      // 签发时间
                .signWith(signatureAlgorithm, secretKey); // 签名算法以及密匙
        if (ttlMillis >= 0) {
            long expMillis = nowMillis + ttlMillis;
            Date expDate = new Date(expMillis);
            builder.setExpiration(expDate); // 过期时间
        }
        return builder.compact();
    }

    /**
     * 验证JWT
     * @param jwtStr
     * @return
     */
    public static CheckResult validateJWT(String jwtStr) {
        CheckResult checkResult = new CheckResult();
        Claims claims = null;
        try {
            claims = parseJWT(jwtStr);
            checkResult.setSuccess(true);
            checkResult.setClaims(claims);
        } catch (ExpiredJwtException e) {
            checkResult.setErrCode(SystemConstant.JWT_ERRCODE_EXPIRE);
            checkResult.setSuccess(false);
        } catch (SignatureException e) {
            checkResult.setErrCode(SystemConstant.JWT_ERRCODE_FAIL);
            checkResult.setSuccess(false);
        } catch (Exception e) {
            checkResult.setErrCode(SystemConstant.JWT_ERRCODE_FAIL);
            checkResult.setSuccess(false);
        }
        return checkResult;
    }

    /**
     * 生成加密Key
     * @return
     */
    public static SecretKey generalKey() {
        byte[] encodedKey = Base64.decode(SystemConstant.JWT_SECERT);
        SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
        return key;
    }

    /**
     * 解析JWT字符串
     * @param jwt
     * @return
     * @throws Exception
     */
    public static Claims parseJWT(String jwt) throws Exception {
        SecretKey secretKey = generalKey();
        return Jwts.parser()
                .setSigningKey(secretKey)
                .parseClaimsJws(jwt)
                .getBody();
    }

    //进行测试的方法
    public static void main(String[] args) throws InterruptedException {
        //小明有效时间 1小时
        User user = new User();
        user.setId(1001l);
        user.setName("123123");
        user.setPassword("111111");
        user.setEdited(new Date());
        String userStr = JSON.toJSONString(user);
        String sc = createJWT("1","20,"+userStr, SystemConstant.JWT_TTL);
        Thread.sleep(3000);
        System.out.println(validateJWT(sc).getClaims().getSubject());
    }

}
5.在model层中定义页面响应的实体类R

package cn.com.fanjingxuan.model;

import java.util.HashMap;
import java.util.Map;

/**
  * @className: R.java
  * @methodName:  R
  * @effect: 页面响应的实体类
  * @author: JingxuanFan
  * @date: 2023/3/19 17:36
  **/
public class R extends HashMap<String, Object> {

    private static final long serialVersionUID = 1L;

    public R() {
        put("code", 0);
    }

    public static R error() {
        return error(500, "未知异常,请联系管理员");
    }

    public static R error(String msg) {
        return error(500, msg);
    }

    public static R error(int code, String msg) {
        R r = new R();
        r.put("code", code);
        r.put("msg", msg);
        return r;
    }

    public static R ok(String msg) {
        R r = new R();
        r.put("msg", msg);
        return r;
    }

    public static R ok(Map<String, Object> map) {
        R r = new R();
        r.putAll(map);
        return r;
    }

    public static R ok() {
        return new R();
    }

    public R put(String key, Object value) {
        super.put(key, value);
        return this;
    }
}
6.在controller层定义JWT登入方法

 /**
      * @className: AdministratorController.java
      * @methodName: login
      * @effect:  定义带token的登入方法
      * @author: JingxuanFan
      * @date: 2023/3/19 16:46
      **/
    @RequestMapping("login")
    @ResponseBody
    public Map<String,Object> login(Administrator administrator, HttpServletRequest request) throws Exception {
        Map<String,Object> result = new HashMap<>();
        //校验用户名和密码
        Administrator admin = administratorService.login(administrator);
        if (admin != null){
            if (admin.getPassword().equals(administrator.getPassword())){
                //将用户信息存储到Session  //登入成功
                HttpSession session = request. getSession();
                session. setAttribute("userInfo", admin);  //1.用于拦截器的判断  2.界面显示用户信息
                result. put("Id", admin.getId());
                //把token返回给客户端-->客户端保存至localStorage-->客户端每次请求附带localStorage参数
                    //SystemConstant.JWT_TTL:token有效时间
                String JWT = JwtUtil.createJWT("1", JSON.toJSONString(admin), SystemConstant.JWT_TTL);
                log.info(JWT);
                result.put("JWT",JWT);
                return result;
            }
            //登录失败 ,密码错误
            result. put("success", false);
            result. put("msg", "密码错误!");
            return result;
        }
        //登录失败,用户名错误或不存在
        result. put("success", false);
        result. put("msg", "用户名错误或不存在!");
        return result;
    }
7.在controller层定义刷新用户token的方法

(与5在同一个类里面)


 /**
      * @className: AdministratorController.java
      * @methodName: refreshToken
      * @effect: 刷新用户token
      * @author: JingxuanFan
      * @date: 2023/3/19 16:38
      **/
    @GetMapping(value = "/refreshToken")
    public Map<String,Object> refreshToken(HttpServletRequest request){
        Map<String,Object> result = new HashMap<>();
        //旧的token令牌
        log.info(request.getHeader("token"));
        Claims claims = JwtUtil.validateJWT(request.getParameter("token")).getClaims();
        String subject = claims.getSubject();
        System.out.println(subject);//20,{"edited":1650100778678,"id":1001,"name":"123123","password":"111111"}
        String JWT = JwtUtil.createJWT(claims.getId(),claims.getSubject(), SystemConstant.JWT_TTL);
        log.info("新token"+JWT);
        result.put("JWT",JWT);
        return result;
    }
8.搭载拦截器权限认证

(在interceptor(拦截器)包中创建自定义拦截器SysInterceptor.java)


package cn.com.fanjingxuan.interceptor;

import cn.com.fanjingxuan.constant.SystemConstant;
import cn.com.fanjingxuan.model.CheckResult;
import cn.com.fanjingxuan.model.R;
import cn.com.fanjingxuan.util.JwtUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
  * @className: SysInterceptor.java
  * @methodName: SysInterceptor
  * @effect: 拦截器 用户权限校验
  * @author: JingxuanFan
  * @date: 2023/3/19 17:25
  **/
public class SysInterceptor implements HandlerInterceptor {

    //日志对象
    private final static Logger logger= LoggerFactory.getLogger(SysInterceptor.class);

    //拦截的核心方法
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        logger.info("执行了拦截的核心方法");
        //获取页面的请求地址
        String contextPath = request.getRequestURI();
        logger.info("路径"+contextPath);
        //判断请求对象中有没有请求方法
        if (handler instanceof HandlerMethod){
            //从请求中取到token令牌
            String authHeader = request.getHeader("token");
            logger.info(authHeader);
            //先判断token令牌是否为空,
            if (StringUtils.isEmpty(authHeader)) {
                logger.info("验证失败,签名验证不存在");
                //调用自定义方法print
                print(response, R.error(SystemConstant.JWT_ERRCODE_NULL,"签名验证不存在"));
                return false;
            }else{
                //验证JWT的签名,返回CheckResult对象,将JWT对象(令牌token)进行解密
                CheckResult checkResult = JwtUtil.validateJWT(authHeader);
                if (checkResult.isSuccess()) {
                    logger.info("签名验证通过");
                    return true;
                } else {
                    switch (checkResult.getErrCode()) {
                        // 签名验证不通过
                        case SystemConstant.JWT_ERRCODE_FAIL:
                            logger.info("签名验证不通过");
                            //调用自定义方法print
                            print(response,R.error(checkResult.getErrCode(),"签名验证不通过"));
                            break;
                        // 签名过期,返回过期提示码
                        case SystemConstant.JWT_ERRCODE_EXPIRE:
                            logger.info("签名过期");
                            //调用自定义方法print
                            print(response,R.error(checkResult.getErrCode(),"签名过期"));
                            break;
                        default:
                            break;
                    }
                    return false;
                }
            }
        }else{
            return true;
        }
    }

    //拦截的执行POST请求的方法
    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
        logger.info("拦截的执行POST请求的方法");
    }

    /**
     * 该方法也是需要当前对应的Interceptor的preHandle方法的返回值为true时才会执行。该方法将在整个请求完成之后,也就是DispatcherServlet渲染了视图执行,
     * 这个方法的主要作用是用于清理资源的,当然这个方法也只能在当前这个Interceptor的preHandle方法的返回值为true时才会执行。
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        logger.info("执行了afterCompletion方法");
    }

    //自定义响应方法
    //将请求处理结果响应回浏览器
    public void print(HttpServletResponse response, Object message){
        try {
            //设置响应头的响应状态
            response.setStatus(HttpStatus.OK.value());
            //设置响应头的响应内容,并转成UTF8
            response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
            //设置头部信息
            response.setHeader("Cache-Control", "no-cache, must-revalidate");
            //字符输出流
            PrintWriter writer = response.getWriter();
            //将message写入到浏览器当中
            writer.write(message.toString());
            //刷新流
            writer.flush();
            //关闭流
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  1. 在config(配置)包下面创建WebAppConfigurer.java,进行拦截配置--调用链

@Configuration 注解可以控制是否开启JWT拦截验证


package cn.com.fanjingxuan.config;

import cn.com.fanjingxuan.interceptor.SysInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

/**
  * @className: WebAppConfigurer.java
  * @methodName:  WebAppConfigurer
  * @effect: 拦截配置--调用链
  * @author: JingxuanFan
  * @date: 2023/3/19 17:57
  **/
// 使用 @Configuration 注解的类就可以被 Spring 识别为配置类,并处理该类上的相关功能注解
@Configuration 
public class WebAppConfigurer extends WebMvcConfigurerAdapter {

    /**
     * 配置不需要拦截和需要拦截的请求
     * @param registry
     */
    //@Override 注解是用来指定方法重写的,只能修饰方法并且只能用于方法重写,不能修饰其它的元素。它可以强制一个子类必须重写父类方法或者实现接口的方法。
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //添加不拦截的方法(登入,注册)
        String[] patterns = new String[] {"/*/login","/administrator/saveT","/employee/saveT"};
        registry.addInterceptor(new SysInterceptor())
                .addPathPatterns("/**")  //先拦截所有方法
                .excludePathPatterns(patterns);  //在拦截的方法中剔除掉 patterns 中的方法(不拦截)
    }
}

三、ApiPost测试

  1. 登入成功生成的token令牌

  1. 不带token令牌执行被拦截的命令

  1. 带token令牌执行被拦截的命令(同一命令)可以查询

四、第二种生成JWT令牌的方法

1.在pom中加入相关依赖

        <!--JWT -->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>4.0.0</version>
        </dependency>
        <dependency>
            <groupId>com.10duke.client.jwt</groupId>
            <artifactId>jjwt</artifactId>
            <version>1.0.0</version>
        </dependency>

2.在utils中加入JWT工具类JwtUtil

package cn.com.fjxuan.utils;

import cn.com.fjxuan.model.User;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.JWTVerifier;
import java.util.Calendar;
import java.util.Map;

/**
 * @className: JwtUtil.java
 * @methodName: JwtUtil
 * @effect: 生成token的工具类
 * @author: JingxuanFan
 * @date: 2023/9/20 21:58
**/
public class JwtUtil {

    /**
     * @methodName testJwtCreate
     * @effect: 生成token
     */
    public static String testJwtCreate(User user) {
        //创建了一个 Calendar 类的实例,表示当前的日期和时间。
        Calendar instance = Calendar.getInstance();
        //设置过期时间:将当前的日期和时间增加了6个月
        instance.add(Calendar.MONTH, 6);
        String token = JWT.create()
                //头可以不指定一般用默认值
                .withClaim("userId", user.getId())
                .withClaim("username", user.getUsername())//payLoad
                .withClaim("pwd", user.getPwd())
                .withExpiresAt(instance.getTime()) //指定令牌的过期时间
                //使用HMAC256算法和密钥"qweqwrpf1"对JWT进行签名。密钥用于验证JWT的完整性。
                .sign(Algorithm.HMAC256("qweqwrpf1")); // Singnature
        //Algorithm.ECDSA256()使用哪种加密算法  括号中写自己指定的密钥

        return token;
    }


    /**
     * @methodName testRequire
     * @effect: 解析token
     * @return
     */
    public static Map<String, Claim> testRequire(String jwt) {
        //require  解密传入加密的签名
        //创建验证对象
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256("qweqwrpf1")).build();
        //使用验证对象中的验证方法  传入生成的JWT串  会返回一个解码的JWT
        DecodedJWT decodedJWT = jwtVerifier.verify(jwt);
        //返回加密对象
        return decodedJWT.getClaims();
    }
}

3.调用工具类生成JWT令牌

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是Spring Boot集成Spring Security、JWT和OAuth2的示例代码: 1. 添加依赖 在pom.xml文件中添加以下依赖: ```xml <!-- Spring Security --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <!-- Spring Security OAuth2 --> <dependency> <groupId>org.springframework.security.oauth</groupId> <artifactId>spring-security-oauth2</artifactId> <version>2.3.7.RELEASE</version> </dependency> <!-- JWT --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.1</version> </dependency> ``` 2. 配置Spring Security 在Spring Boot应用程序中,可以通过配置类来配置Spring Security。创建一个配置类,命名为SecurityConfig.java,并添加以下内容: ```java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsService userDetailsService; @Autowired private PasswordEncoder passwordEncoder; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder); } @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests().antMatchers("/oauth/**").permitAll() .anyRequest().authenticated() .and().formLogin().permitAll(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } } ``` 这个类配置了Spring Security,启用了Web安全性,并定义了一个UserDetailsService实例,该实例将用于验证用户。 3. 配置OAuth2 创建一个OAuth2配置类,命名为OAuth2Config.java,并添加以下内容: ```java @Configuration @EnableAuthorizationServer public class OAuth2Config extends AuthorizationServerConfigurerAdapter { @Autowired private AuthenticationManager authenticationManager; @Autowired private UserDetailsService userDetailsService; @Autowired private DataSource dataSource; @Autowired private PasswordEncoder passwordEncoder; @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.jdbc(dataSource); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints.authenticationManager(authenticationManager) .userDetailsService(userDetailsService) .accessTokenConverter(accessTokenConverter()); } @Bean public TokenStore tokenStore() { return new JdbcTokenStore(dataSource); } @Bean public JwtAccessTokenConverter accessTokenConverter() { JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); converter.setSigningKey("secret"); return converter; } @Override public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception { oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()"); } @Bean public ClientDetailsService clientDetailsService() { return new JdbcClientDetailsService(dataSource); } @Bean public ApprovalStore approvalStore() { return new JdbcApprovalStore(dataSource); } } ``` 这个类配置了OAuth2服务端,启用了授权服务器,并定义了一个客户端详情服务实例,该实例将用于管理客户端的详细信息。它还定义了一个令牌存储实例,该实例将用于存储访问令牌。 4. 配置JWT 创建一个JWT配置类,命名为JwtConfig.java,并添加以下内容: ```java @Configuration public class JwtConfig { @Value("${jwt.secret}") private String secret; @Bean public Key key() { return Keys.hmacShaKeyFor(secret.getBytes()); } @Bean public JwtDecoder jwtDecoder() { return NimbusJwtDecoder.withSecretKey(key()).build(); } @Bean public JwtEncoder jwtEncoder() { return NimbusJwtEncoder.withSecretKey(key()).build(); } } ``` 这个类配置了JWT,定义了一个秘钥,该秘钥将用于签署和验证JWT令牌。 5. 配置资源服务器 创建一个资源服务器配置类,命名为ResourceServerConfig.java,并添加以下内容: ```java @Configuration @EnableResourceServer public class ResourceServerConfig extends ResourceServerConfigurerAdapter { @Autowired private JwtAccessTokenConverter accessTokenConverter; @Override public void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/api/**").authenticated() .anyRequest().permitAll(); } @Override public void configure(ResourceServerSecurityConfigurer resources) throws Exception { resources.tokenStore(tokenStore()).accessTokenConverter(accessTokenConverter); } @Bean public TokenStore tokenStore() { return new JwtTokenStore(accessTokenConverter); } } ``` 这个类配置了资源服务器,启用了资源服务器,并定义了一个令牌存储实例,该实例将用于存储访问令牌。 6. 创建实体类 创建一个User实体类,命名为User.java,并添加以下内容: ```java @Entity @Table(name = "users") public class User implements UserDetails { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(unique = true) private String username; private String password; @ElementCollection(fetch = FetchType.EAGER) private List<String> roles; @Override public Collection<? extends GrantedAuthority> getAuthorities() { return roles.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList()); } @Override public String getPassword() { return password; } @Override public String getUsername() { return username; } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return true; } } ``` 这个类定义了一个用户实体,实现了UserDetails接口,该接口提供了有关用户的详细信息。 7. 创建数据访问对象 创建一个UserRepository接口,命名为UserRepository.java,并继承JpaRepository接口,添加以下内容: ```java @Repository public interface UserRepository extends JpaRepository<User, Long> { Optional<User> findByUsername(String username); } ``` 这个接口定义了一个用户数据访问对象,用于管理用户。 8. 实现用户服务 创建一个UserServiceImpl类,命名为UserServiceImpl.java,并添加以下内容: ```java @Service public class UserServiceImpl implements UserDetailsService { @Autowired private UserRepository userRepository; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { return userRepository.findByUsername(username) .orElseThrow(() -> new UsernameNotFoundException("User not found")); } } ``` 这个类实现了UserDetailsService接口,该接口提供了一个方法,根据用户名加载用户信息。 9. 创建控制器 创建一个UserController类,命名为UserController.java,并添加以下内容: ```java @RestController @RequestMapping("/api") public class UserController { @GetMapping("/users") public List<User> getUsers() { return userRepository.findAll(); } @PostMapping("/users") public User createUser(@RequestBody User user) { user.setPassword(passwordEncoder.encode(user.getPassword())); return userRepository.save(user); } @Autowired private UserRepository userRepository; @Autowired private PasswordEncoder passwordEncoder; } ``` 这个类定义了一个RESTful API控制器,用于管理用户。 10. 测试 启动应用程序,并使用Postman测试API接口。例如,使用POST方法向/api/users端点发送请求,创建一个新用户。 这就是Spring Boot集成Spring Security、JWT和OAuth2的示例代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值