springboot+springsecurity+jwt前后端分离

本文介绍如何使用 Spring Security 和 JWT 实现一个安全的 Web 应用程序,包括自定义用户详情服务、密码编码器、JWT 工具类、过滤器等组件的实现方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

maven 依赖

selfUserDetails

SelfUserDetailsService

DefaultPasswordEncoder

JwtTokenUtil

MyAccessDenieDHandler

TokenAuthenticationFilter

TokenLoginFilter

UnauthorizedEntryPorint


maven 依赖

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

文件目录

 

SpringSecurityConfig

public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    DefaultPasswordEncoder defaultPasswordEncoder;
    @Autowired
   SelfUserDetailsService selfUserDetailsService;
   @Autowired
   AppFilterInvocationSecurityMetadataSource appFilterInvocationSecurityMetadataSource;
   @Autowired
   CustomerAccessDecisionManger customerAccessDecisionManger;
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 加入自定义的安全认证
//        auth.authenticationProvider(provider);

        auth.userDetailsService(selfUserDetailsService).passwordEncoder(new BCryptPasswordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .exceptionHandling()

                //未授权处理
                .authenticationEntryPoint(new UnauthorizedEntryPoint())
                .accessDeniedHandler(new MyAccessDeniedHandler())
                .and().authorizeRequests().withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
            @Override
            public <O extends FilterSecurityInterceptor> O postProcess(O o) {
                o.setSecurityMetadataSource(appFilterInvocationSecurityMetadataSource);
                o.setAccessDecisionManager(customerAccessDecisionManger);
                return o;
            }
        })
                .anyRequest().authenticated()
                .and().csrf().disable()
                .logout().logoutUrl("/logout")
                .and()
                //.addLogoutHandler(new TokenLogoutHandler(tokenManager))
                .addFilter(new TokenAuthenticationFilter(authenticationManager()))
                .addFilter(new TokenLoginFilter(authenticationManager())).httpBasic();
    }

    @Bean
    protected AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager();
    }
@Bean
    public DefaultPasswordEncoder CreateEncoder(){
        return new DefaultPasswordEncoder();
}

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/Account/**","/index**", "/swagger-ui.html/**");
    }

}

selfUserDetails

@Data
@Accessors(chain = true)
public class SelfUserDetails implements UserDetails {
    private Set<? extends GrantedAuthority> authorities;//角色配置类
    private Account account;//用户实体

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return this.authorities;
    }


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

    @Override
    public String getUsername() {
        return this.account.getName();
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
    public void select(String name){
        Account name1 = new Account().selectOne((Wrapper) new MyWrapper().eq("name", name));
        this.account=name1;
    }
}

SelfUserDetailsService

@Component

public class SelfUserDetailsService implements UserDetailsService {
   private String roleName=null;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        SelfUserDetails selfUserDetails = new SelfUserDetails();
        selfUserDetails.select(username);
        if(selfUserDetails.getAccount()==null){
            //仍需要细化处理
            throw new UsernameNotFoundException("该用户不存在");
        }
        Set authoritiesSet = new HashSet();
        // 模拟从数据库中获取用户角色
        Userbyrole userbyrole = new Userbyrole().selectOne((Wrapper) new MyWrapper().eq("userid", selfUserDetails.getAccount().getId()));
        GrantedAuthority authority = new SimpleGrantedAuthority(userbyrole.getRole().toString());
         this.roleName=userbyrole.getRole().toString();
        authoritiesSet.add(authority);
    selfUserDetails.setAuthorities(authoritiesSet);
    return selfUserDetails;
    }
    public String getRoleName(){
        return this.roleName;
    }
}

DefaultPasswordEncoder


@Slf4j
public class DefaultPasswordEncoder extends BCryptPasswordEncoder {
    @Override
    public String encode(CharSequence rawPassword) {
        return rawPassword.toString();
    }

    @Override
    public boolean matches(CharSequence rawPassword, String encodedPassword) {
        if (rawPassword == null) {
            throw new IllegalArgumentException("rawPassword cannot be null");
        }
        if (encodedPassword == null || encodedPassword.length() == 0) {
            log.error("Empty encoded password");
            throw new IllegalArgumentException("encodedPassword is null");
        }
        return encodedPassword.equals(rawPassword);
    }
}

JwtTokenUtil

public class JwtTokenUtil {
    private static long tokenExpiration = 24 * 60 * 60 * 1000;
    private static String tokenSignKey = "123456";
    private static String userRoleKey = "userRole";

    public String createToken(String userName) {
        String token = Jwts.builder().setSubject(userName)
                .setExpiration(new Date(System.currentTimeMillis() + tokenExpiration))
                .signWith(SignatureAlgorithm.HS512, tokenSignKey).compressWith(CompressionCodecs.GZIP).compact();
        return token;
    }

    public static String createToken(String userName, String role) {
        String token = Jwts.builder().setSubject(userName)
                .claim(userRoleKey, role)
                .setExpiration(new Date(System.currentTimeMillis() + tokenExpiration))
                .signWith(SignatureAlgorithm.HS512, tokenSignKey).compressWith(CompressionCodecs.GZIP).compact();
        return token;
    }

    public static String getUserNameFromToken(String token) {
        String userName = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token).getBody().getSubject();
        return userName;
    }

    public static String getUserRoleFromToken(String token) {
        Claims claims = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token).getBody();
        return claims.get(userRoleKey).toString();
    }


}

MyAccessDenieDHandler

public class MyAccessDeniedHandler implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
      response.setStatus(403);
        ResponseUtil.out(response, Result.failed("权限不足"));
    }
}

TokenAuthenticationFilter

public class TokenAuthenticationFilter extends BasicAuthenticationFilter {




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


    private void  PassUp(HttpServletRequest request, HttpServletResponse response, FilterChain chain, String... url) throws IOException, ServletException {
        for (int i = 0; i < url.length; i++) {
            if(request.getRequestURL().indexOf(url[i])!=-1)
                chain.doFilter(request,response);
        }
    }

    private void NotAllowed(HttpServletRequest request, HttpServletResponse response, FilterChain chain){
        if(!request.getMethod().contains("POST")){//必须是POST请求
            try{
                ResponseUtil.out(response, Result.failed("不是POST!"));

                chain.doFilter(request,response);
            }catch (Exception e) {
                logger.debug(e.getMessage());
            }
        }
    }


   private void TokenVerify(HttpServletRequest request, HttpServletResponse response, FilterChain chain){
       UsernamePasswordAuthenticationToken authenticationToken=null;
       try{
           authenticationToken=getAuthentication(request);//或取请求中的Token信息
           if (authenticationToken != null) {//Token令牌为null
               SecurityContextHolder.getContext().setAuthentication(authenticationToken);
           } else {
               ResponseUtil.out(response, Result.failed("鉴权失败"));
           }

       }catch (Exception e){
           e.printStackTrace();
           ResponseUtil.out(response, Result.failed(e.getMessage()));
       }
       try{
           chain.doFilter(request, response);
       }catch (Exception e){
           logger.debug(e.getMessage());
       }
   }
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {

         logger.info("==========================="+request.getRequestURL());
         PassUp(request,response,chain,"index");
         NotAllowed(request,response,chain);
        TokenVerify(request,response,chain);

    }
    private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
        // 获取Token字符串,token 置于 header 里
        String token = request.getHeader("token");
        if (!StringUtils.hasText(token)) {
            token = request.getParameter("token");
        }
        if (token != null && !"".equals(token.trim())) {
            // 从Token中解密获取用户名
            String userName = JwtTokenUtil.getUserNameFromToken(token);

            if (userName != null) {
                // 从Token中解密获取用户角色
                String role = JwtTokenUtil.getUserRoleFromToken(token);
                // 将ROLE_XXX,ROLE_YYY格式的角色字符串转换为数组
                String[] roles = role.split(",");
                Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
                for (String s : roles) {
                    authorities.add(new SimpleGrantedAuthority(s));
                }
                return new UsernamePasswordAuthenticationToken(userName, token, authorities);
            }
            return null;
        }
        return null;
    }
}

TokenLoginFilter

@Slf4j
public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {
    private AuthenticationManager authenticationManager;
    private AuthenticationException authentication;
    public TokenLoginFilter(AuthenticationManager authenticationManager) {
        this.authenticationManager =authenticationManager;
    }

    @SneakyThrows
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        try {


            String username = request.getParameter("username");

            String password = request.getParameter("password");

            username = username != null ? username.trim() : "";
            password = password != null ? password : "";
            return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password, new ArrayList<>()));
        } catch (Exception e) {

            new RuntimeException(e);

            this.unsuccessfulAuthentication(request,response, (AuthenticationException) authentication);
            return null;
        }

    }
    /**
     * 登录成功
     */
    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication auth) throws IOException, ServletException {

        SelfUserDetails user= (SelfUserDetails) auth.getPrincipal();
        Account account = user.getAccount();
        String authrorities = user.getAuthorities().size() > 0 ? user.getAuthorities().toString().replaceAll("(?:\\[|null|\\]| +)", "") : user.getAuthorities().toString();
        String token=JwtTokenUtil.createToken(account.getName(),authrorities);
        HashMap<Object, Object> map = new HashMap<>();
        map.put("token", token);
        map.put("user",account);

        ResponseUtil.out(response, Result.successWithData(map));
    }
    /**
     * 登录失败
     */
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
        logger.debug("登录失败!");
        ResponseUtil.out(response, Result.failed("登录失败"));
    }
}

UnauthorizedEntryPorint

public class UnauthorizedEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
         ResponseUtil.out(httpServletResponse, Result.failed("未授权统一处理"));
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值