JWT在Spring Security中的实战应用:认证、授权一网打尽

一:JWT介绍

1.什么是JWT

1)官方:

JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA .

2)介绍:

JSON Web 令牌(JWT)是一种开放标准(RFC 7519) ,它定义了一种紧凑和自包含的方式,用于作为 JSON 对象在各方之间安全地传输信息。可以验证和信任此信息,因为它是数字签名的。JWTs 可以使用 secret (使用 HMAC 算法)或使用 RSA 或 ECDSA 的公钥/私钥对进行签名。 通俗的解释:JWT简称 JSON Web Token,也就是JSON形式作为Web应用中的令牌信息,用于在各方之间安全的将信息作为JSON对象传输,在数据传输过程中可以完成数据加密,签名等操作。

2.基于Session认证

我们最先接触到的认证方式就是基于Session的认证方式,每一个会话在服务端都会存储在HttpSession中,相当于一个Map,然后通过Cookie的形式给客户端返回一个jsessionid,然后每次访问的时候都需要从HttpSession中根据jsessionid来获取,通过这个逻辑来判断是否是认证的状态。

存在的问题:

  • 每个用户都需要做一次记录,而Session一般情况下都会存在内存中,增大了服务器的开销
  • 集群环境下Session需要同步,或者分布式Session来处理
  • 因为是基于Cookie来传输的,如果Cookie被解惑,用户容易受到CSRF攻击。
  • 前后端分离项目中会更加的麻烦

3.基于JWT的认证

1)具体流程

2)认证的流程:

  • 用户通过表单把账号密码提交到后端服务后,如果认证成功就会生成一个对应的Token信息
  • 之后用户请求资源都会携带这个Token值,后端获取到后校验通过放行,校验不通过拒绝

3)jwt的优势:

  • 简介:可以通过URL,POST参数或者HTTP header发送,因为数据量小,传输速度快。
  • 自包含:负载中包含了所有用户所需的信息,避免多次查询数据
  • 夸语言:以JSON形式保存在客户端。
  • 不需要服务端保存信息,适合分布式环境。

4.JWT的结构

1)令牌的组成:

  • 标头(Header)
  • 有效载荷(Payload)
  • 签名(Signature)
  • 因此JWT的格式为:xxxx.yyyy.zzzz Header.Payload.Signature

2)Header:

header通常由两部分组成:令牌的类型【JWT】和所使用的签名算法。例如HMAC、SHA256或者RSA,它会使用 Base64 编码组成 JWT结构的第一部分。注意:Base64是一种编码,是可以被翻译回原来的样子的。

java 复制代码
{
   "alg":"HS256",
   "typ":"JWT"
}

3)Payload:

令牌的第二部分是有效负载,其中包含声明,声明是有关实体(通常是用户信息)和其他数据的声明,它会使用Base64来编码,组成JWT结构的第二部分。

java 复制代码
{
 "userId":"9527",
 "userName":"随意时光",
}

因为会通过Base64编码,所以不要把用户私人信息写在Payload中。

4)Signature:

签名部分,前面两部分都是使用 Base64 进行编码的,即前端可以解开header和payload中的信息,Signature需要使用编码后的 header 和 payload 以及我们提供的一个签名,然后使用 header 中指定的前面算法(HS256) 进行签名,签名的作用是保证 JWT 没有被篡改过。

二:JWT实现

1.JWT基本实现

1)生成Token令牌

java 复制代码
    /**
     * 生成Token信息
     */
    @Test
    void generatorToke() {
        Map<String,Object> map = new HashMap<>();
        map.put("alg","HS256");
        map.put("typ","JWT");
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.SECOND,60);
        String token = JWT.create()
                .withHeader(map) // 设置header
                .withClaim("userid", 666) // 设置 payload
                // 设置过期时间
                .withExpiresAt(calendar.getTime())
                .withClaim("username", "波波烤鸭") // 设置 payload
                .sign(Algorithm.HMAC256("qwaszx")); // 设置签名  保密
        System.out.println(token);
    }

2)根据Token来验证是否正确

java 复制代码
/**
     * 验证Token信息
     */
    @Test
    public void verifier(){
        String t o k e n = '浏览器的传输过来的';
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256("qwaszx")).build();
        DecodedJWT verify = jwtVerifier.verify(token);
        System.out.println(verify.getClaim("userid").asInt());
        System.out.println(verify.getClaim("username").asString());
    }

3)验证中场景的异常信息:

  • SignatureVerificationException 签名不一致异常
  • TokenExpiredException Token过期异常
  • AlgorithmMismatchException 算法不匹配异常
  • InvalidClaimException 失效的payload异常

2.JWT封装

为了简化操作我们可以对上面的操作进一步封装来简化处理

java 复制代码
package com.bobo.jwt.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;

import java.util.Calendar;
import java.util.Map;

/**
 * JWT操作的工具类
 */
public class JWTUtils {
    private static final String SING = "123qwaszx";

    /**
     * 生成Token  header.payload.sing 组成
     * @return
     */
    public static String getToken(Map<String,String> map){
        Calendar instance = Calendar.getInstance();
        instance.add(Calendar.DATE,7); // 默认过期时间 7天
        JWTCreator.Builder builder = JWT.create();
        // payload 设置
        map.forEach((k,v)->{
            builder.withClaim(k,v);
        });
        // 生成Token 并返回
        return builder.withExpiresAt(instance.getTime())
                    .sign(Algorithm.HMAC256(SING));
    }

    /**
     * 验证Token
     * @return
     *     DecodedJWT  可以用来获取用户信息
     */
    public static DecodedJWT verify(String token){
        // 如果不抛出异常说明验证通过,否则验证失败
        return JWT.require(Algorithm.HMAC256(SING)).build().verify(token);
    }
}

3.SpringBoot应用

1) 首先是在登录方法中,如果登录成功,我们需要生成对应的Token信息,然后将Token信息响应给客户端。

java 复制代码
@PostMapping("/login")
    public Map<String,Object> login(User user){
        Map<String,Object> res = new HashMap<>();
        if("zhang".equals(user.getUserName()) && "123".equals(user.getPassword())){
            // 登录成功
            Map<String,String> map = new HashMap<>();
            map.put("userid","1");
            map.put("username","zhang");
            String token = JWTUtils.getToken(map);
            res.put("flag",true);
            res.put("msg","登录成功");
            res.put("token",token);
            return res;
        }
        res.put("flag",false);
        res.put("msg","登录失败");
        return res;
    }

2)然后就是用户提交请求的时候需要携带Token信息,然后我们在controller中处理请求之前需要对token做出校验。如果验证通过就继续处理请求,否则就拦截该请求。

java 复制代码
  @PostMapping("/queryUser")
    public Map<String,Object> queryUser(@RequestParam("token") String token){
        // 获取用信息之前校验
        Map<String,Object> map = new HashMap<>();
        try{
            DecodedJWT verify = JWTUtils.verify(token);
            map.put("state",true);
            map.put("msg","请求成功");
            return map;
        }catch (SignatureVerificationException e){
            e.printStackTrace();
            map.put("msg","无效签名");
        }catch (TokenExpiredException e){
            e.printStackTrace();
            map.put("msg","Token过期");
        }catch (AlgorithmMismatchException e){
            e.printStackTrace();
            map.put("msg","算法不一致");
        }catch (Exception e){
            e.printStackTrace();
            map.put("msg","Token无效");
        }
        map.put("state",false);
        return map;
    }

4.自定义的拦截器

1)但是上面的情况我们看到在controller中添加了大幅度的Token校验的代码,增大的冗余代码,这时我们可以考虑把Token校验的代码放在拦截器中处理。我们创建一个自定义的拦截器.

java 复制代码
/**
 * 自定义的拦截器
 *     对特定的情况校验是否携带的有Token信息,如果不携带直接拒绝
 *     然后对Token校验合法性
 */
public class JWTInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String token = request.getParameter("token");
        // 获取用信息之前校验
        Map<String,Object> map = new HashMap<>();
        try{
            DecodedJWT verify = JWTUtils.verify(token);
            return true;
        }catch (SignatureVerificationException e){
            e.printStackTrace();
            map.put("msg","无效签名");
        }catch (TokenExpiredException e){
            e.printStackTrace();
            map.put("msg","Token过期");
        }catch (AlgorithmMismatchException e){
            e.printStackTrace();
            map.put("msg","算法不一致");
        }catch (Exception e){
            e.printStackTrace();
            map.put("msg","Token无效");
        }
        map.put("state",false);
        // 把Map转换为JSON响应
        String json = new ObjectMapper().writeValueAsString(map);
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().println(json);
        return false;
    }
}

2)要让拦截器生效我们还需要添加对应的配置类。

java 复制代码
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new JWTInterceptor())
                .addPathPatterns("/queryUser") // 需要拦截的请求
                .addPathPatterns("/saveUser") // 需要拦截的请求
                .excludePathPatterns("/login"); // 需要排除的请求
    }
}

3)然后添加一个测试的方法 /saveUser

java 复制代码
@PostMapping("/saveUser")
    public String saveUser(){
        System.out.println("------------>");
        return "success";
    }

三:SpringSecurity基于JWT实现Token的处理

前面介绍了手写单点登录和JWT的应用,本文结合SpringSecurity来介绍下在SpringBoot项目中基于SpringSecurity作为认证授权框架的情况下如何整合JWT来实现Token的处理。

1.认证思路分析

SpringSecurity主要是通过过滤器来实现功能的!我们要找到SpringSecurity实现认证和校验身份的过滤器!

1)回顾集中式认证流程

用户认证 :使用 UsernamePasswordAuthenticationFilter过滤器中 attemptAuthentication方法实现认证功能,该过滤器父类中 successfulAuthentication方法实现认证成功后的操作。认证失败是在 unsuccessfulAuthentication 身份校验 :使用 BasicAuthenticationFilter 过滤器中 doFilterInternal方法验证是否登录,以决定能否进入后续过滤器。

2)分析分布式认证流程

用户认证 :由于分布式项目,多数是前后端分离的架构设计,我们要满足可以接受异步post的认证请求参数,需要修改UsernamePasswordAuthenticationFilter过滤器中attemptAuthentication方法,让其能够接收请求体。  另外,默认successfulAuthentication方法在认证通过后,是把用户信息直接放入session就完事了,现在我们需要修改这个方法,在认证通过后生成token并返回给用户。 身份校验:原来BasicAuthenticationFilter过滤器中doFilterInternal方法校验用户是否登录,就是看session中是否有用户信息,我们要修改为,验证用户携带的token是否合法,并解析出用户信息,交给SpringSecurity,以便于后续的授权功能可以正常使用。

2.具体实现

1)创建一个SpringBoot项目.引入必要的依赖

yaml 复制代码
<dependencies>
        <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>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.bobo</groupId>
            <artifactId>security-jwt-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.80</version>
        </dependency>
 <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.4.0</version>
        </dependency>
    </dependencies>

2)引入前面创建的JWT的工具类

java 复制代码
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.AlgorithmMismatchException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;

import java.security.SignatureException;
import java.util.Calendar;
import java.util.Map;

public class JWTUtils {
    private static final String SING = "123qwaszx";

    /**
     * 生成Token  header.payload.sing 组成
     * @return
     */
    public static String getToken(Map<String,String> map){
        Calendar instance = Calendar.getInstance();
        instance.add(Calendar.DATE,7); // 默认过期时间 7天
        JWTCreator.Builder builder = JWT.create();
        // payload 设置
        map.forEach((k,v)->{
            builder.withClaim(k,v);
        });
        // 生成Token 并返回
        return builder.withExpiresAt(instance.getTime())
                .sign(Algorithm.HMAC256(SING));
    }

    /**
     * 验证Token
     * @return
     *     DecodedJWT  可以用来获取用户信息
     */
    public static DecodedJWT verify(String token){
        // 如果不抛出异常说明验证通过,否则验证失败
        DecodedJWT verify = null;
        try {
            verify = JWT.require(Algorithm.HMAC256(SING)).build().verify(token);
        }catch (SignatureVerificationException e){
            e.printStackTrace();
        }catch (AlgorithmMismatchException e){
            e.printStackTrace();
        }catch (Exception e){
            e.printStackTrace();
        }
        return verify;
    }
}

3)创建用户的实例,添加必要的属性

java 复制代码
@Data
public class UserPojo implements UserDetails {

    private Integer id;

    private String username;

    private String password;

    private Integer status;


    @JsonIgnore
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        List<SimpleGrantedAuthority> auth = new ArrayList<>();
        auth.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
        return auth;
    }

    @Override
    public String getPassword() {
        return this.password;
    }

    @Override
    public String getUsername() {
        return this.username;
    }
    @JsonIgnore
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }
    @JsonIgnore
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }
    @JsonIgnore
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }
    @JsonIgnore
    @Override
    public boolean isEnabled() {
        return true;
    }
}

4)完成基于SpringSecurity的数据库认证。创建UserService接口并实现

java 复制代码
public interface UserService extends UserDetailsService {
}

@Service
public class UserServiceImpl implements UserService {
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        UserPojo userPojo = new UserPojo();
        if("zhang".equals(username)){
            userPojo.setUsername("zhang");
            userPojo.setPassword("$2a$10$hbMJRuxJoa6kWcfeT7cNPOGdoEXm5sdfSm5DQtp//2cmCF0MHO8b6");
            return userPojo;
        }
        return userPojo;
    }
}

5)自定义认证过滤器

在SpringSecurity中的认证是通过UsernamePasswordAuthenticationFilter来处理的,现在我们要通过JWT来处理,那么我们就需要重写其中几个处理的方法

1.认证的逻辑还是走的UserService处理,但是我们需要自己来手动的调用认证逻辑。
java 复制代码
 @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException {

        UserPojo sysUser = null;
        try {
            sysUser = JSON.parseObject(getJson(request), UserPojo.class);
        } catch (IOException e) {
            e.printStackTrace();
        }
        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(sysUser.getUsername(), sysUser.getPassword());
        this.setDetails(request, authRequest);
        return authenticationManager.authenticate(authRequest);
    }

    public String getJson(HttpServletRequest request) throws IOException{
        BufferedReader streamReader = new BufferedReader( new InputStreamReader(request.getInputStream(), "UTF-8"));
        StringBuilder sb = new StringBuilder();
        String inputStr;
        while ((inputStr = streamReader.readLine()) != null) {
            sb.append(inputStr);
        }
        return sb.toString();
    }
2.认证成功生成Token信息,并保存在响应的header头中
java 复制代码
@Override
    protected void successfulAuthentication(HttpServletRequest request
            , HttpServletResponse response
            , FilterChain chain
            , Authentication authResult) throws IOException, ServletException {
        // 生成Token信息
        Map<String,String> map = new HashMap<>();
        map.put("username",authResult.getName());
        Collection<? extends GrantedAuthority> authorities = authResult.getAuthorities();
        List<String> list = new ArrayList<>();
        for (GrantedAuthority authority : authorities) {
            list.add(authority.getAuthority());
        }
        map.put("roles", JSON.toJSONString(list));
        String token = JWTUtils.getToken(map);
        response.addHeader("Authorization","Bearer"+token);
        try {
            response.setContentType("application/json;charset=utf-8");
            response.setStatus(HttpServletResponse.SC_OK);
            PrintWriter out = response.getWriter();
            Map<String,Object> resultMap = new HashMap();
            resultMap.put("code", HttpServletResponse.SC_OK);
            resultMap.put("msg", "认证通过!");
            out.write(JSON.toJSONString(resultMap));
            out.flush();
            out.close();
        }catch (Exception outEx){
            outEx.printStackTrace();
        }
    }
3.认证失败
java 复制代码
@Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
        try {
            response.setContentType("application/json;charset=utf-8");
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            PrintWriter out = response.getWriter();
            Map resultMap = new HashMap();
            resultMap.put("code", HttpServletResponse.SC_UNAUTHORIZED);
            resultMap.put("msg", "用户名或密码错误!");
            out.write(new ObjectMapper().writeValueAsString(resultMap));
            out.flush();
            out.close();
        }catch (Exception outEx){
            outEx.printStackTrace();
        }
    }
4.完整代码:
java 复制代码
package com.bobo.jwt.filter;

public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {

    private  AuthenticationManager authenticationManager;
    public TokenLoginFilter(AuthenticationManager authenticationManager){
        this.authenticationManager = authenticationManager;
    }

    /**
     * 具体认证的方法
     * @param request
     * @param response
     * @return
     * @throws AuthenticationException
     */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException {

        UserPojo sysUser = null;
        try {
            sysUser = JSON.parseObject(getJson(request), UserPojo.class);
        } catch (IOException e) {
            e.printStackTrace();
        }
        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(sysUser.getUsername(), sysUser.getPassword());
        this.setDetails(request, authRequest);
        return authenticationManager.authenticate(authRequest);
    }

    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
        try {
            response.setContentType("application/json;charset=utf-8");
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            PrintWriter out = response.getWriter();
            Map resultMap = new HashMap();
            resultMap.put("code", HttpServletResponse.SC_UNAUTHORIZED);
            resultMap.put("msg", "用户名或密码错误!");
            out.write(new ObjectMapper().writeValueAsString(resultMap));
            out.flush();
            out.close();
        }catch (Exception outEx){
            outEx.printStackTrace();
        }
    }

    public String getJson(HttpServletRequest request) throws IOException{
        BufferedReader streamReader = new BufferedReader( new InputStreamReader(request.getInputStream(), "UTF-8"));
        StringBuilder sb = new StringBuilder();
        String inputStr;
        while ((inputStr = streamReader.readLine()) != null) {
            sb.append(inputStr);
        }
        return sb.toString();
    }



    /**
     * 登录成功后的处理
     * @param request
     * @param response
     * @param chain
     * @param authResult
     * @throws IOException
     * @throws ServletException
     */
    @Override
    protected void successfulAuthentication(HttpServletRequest request
            , HttpServletResponse response
            , FilterChain chain
            , Authentication authResult) throws IOException, ServletException {
        // 生成Token信息
        Map<String,String> map = new HashMap<>();
        map.put("username",authResult.getName());
        Collection<? extends GrantedAuthority> authorities = authResult.getAuthorities();
        List<String> list = new ArrayList<>();
        for (GrantedAuthority authority : authorities) {
            list.add(authority.getAuthority());
        }
        map.put("roles", JSON.toJSONString(list));
        String token = JWTUtils.getToken(map);
        response.addHeader("Authorization","Bearer"+token);
        try {
            response.setContentType("application/json;charset=utf-8");
            response.setStatus(HttpServletResponse.SC_OK);
            PrintWriter out = response.getWriter();
            Map<String,Object> resultMap = new HashMap();
            resultMap.put("code", HttpServletResponse.SC_OK);
            resultMap.put("msg", "认证通过!");
            out.write(JSON.toJSONString(resultMap));
            out.flush();
            out.close();
        }catch (Exception outEx){
            outEx.printStackTrace();
        }
    }
}

6)自定义校验过滤器

然后就是当客户端提交请求,我们需要拦截请求检查header头中是否携带了对应的Token信息,并检查是否合法。

java 复制代码
/**
 * 校验Token是否合法的Filter
 */
public class TokenVerifyFilter  extends BasicAuthenticationFilter {


    public TokenVerifyFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        String header = request.getHeader("Authorization");
        if (header == null || !header.startsWith("Bearer")) {
            //如果携带错误的token,则给用户提示请登录!
            chain.doFilter(request, response);
            response.setContentType("application/json;charset=utf-8");
            response.setStatus(HttpServletResponse.SC_FORBIDDEN);
            PrintWriter out = response.getWriter();
            Map resultMap = new HashMap();
            resultMap.put("code", HttpServletResponse.SC_FORBIDDEN);
            resultMap.put("msg", "请登录!");
            out.write(JSON.toJSONString(resultMap));
            out.flush();
            out.close();
        } else {
            //如果携带了正确格式的token要先得到token
            String token = header.replace("Bearer", "");
            //验证tken是否正确
            DecodedJWT verify = JWTUtils.verify(token);
            String userName = verify.getClaim("username").asString();
            String roleJSON = verify.getClaim("roles").asString();
            System.out.println("roleJSON = " + roleJSON);
            List<String> roleArray = JSON.parseArray(roleJSON,String.class);
            List<SimpleGrantedAuthority> list = new ArrayList<>();
            for (String s : roleArray) {
                list.add(new SimpleGrantedAuthority(s));
            }
            UsernamePasswordAuthenticationToken authResult =
                    new UsernamePasswordAuthenticationToken(userName, null, list);
            SecurityContextHolder.getContext().setAuthentication(authResult);
            chain.doFilter(request, response);

        }
    }
}

7)配置类

然后我们需要添加SpringSecurity的配置类,添加自定义的过滤器

java 复制代码
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SpringSecurityWebConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private UserService userService;


    @Bean
    public BCryptPasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    //指定认证对象的来源
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
    }
    //SpringSecurity配置信息
    public void configure(HttpSecurity http) throws Exception {
        http.csrf()
                .disable()
                .authorizeRequests()
                .antMatchers("/user/query").hasAnyRole("ADMIN")
                .anyRequest()
                .authenticated()
                .and()
                .addFilter(new TokenLoginFilter(super.authenticationManager()))
                .addFilter(new TokenVerifyFilter(super.authenticationManager()))
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }
}

8)Controller

为了便于测试,我们添加了一个Controller,如下:

java 复制代码
@RestController
public class UserController {

    @PreAuthorize(value = "hasAnyRole('ROLE_ADMIN')")
    @GetMapping("/query")
    public String query(){
        System.out.println("---------->query");
        return "query .... ";
    }

    @PreAuthorize(value = "hasAnyRole('ROOT')")
    @GetMapping("/update")
    public String update(){
        System.out.println("---------->update");
        return "update .... ";
    }

    @GetMapping("/save")
    public String save(){
        System.out.println("---------->save");
        return "save .... ";
    }
}
相关推荐
崎岖Qiu1 小时前
【JVM篇11】:分代回收与GC回收范围的分类详解
java·jvm·后端·面试
许苑向上3 小时前
Spring Boot 自动装配底层源码实现详解
java·spring boot·后端
超级小忍6 小时前
深入浅出:在 Spring Boot 中构建实时应用 - 全面掌握 WebSocket
spring boot·后端·websocket
没有bug.的程序员6 小时前
《Spring Security源码深度剖析:Filter链与权限控制模型》
java·后端·spring·security·filter·权限控制
无责任此方_修行中7 小时前
不止是 AI 热潮:AWS 2025 技术峰会带给我的思考
后端·架构·aws
lang201509287 小时前
Apache Ignite 与 Spring Boot 集成
spring boot·后端·apache·ignite
Asthenia04127 小时前
深入剖析 Spring Boot 请求处理链路与 Servlet 的本质
后端
旧时光巷7 小时前
【Flask 基础 ①】 | 路由、参数与模板渲染
后端·python·零基础·flask·web·模板渲染·路由系统
小醉你真好7 小时前
Spring Boot 数据源配置中为什么可以不用写 driver-class-name
spring boot·后端·源代码管理
SirLancelot18 小时前
数据结构-Set集合(一)Set集合介绍、优缺点
java·开发语言·数据结构·后端·算法·哈希算法·set