SpringBoot2.0整合SpringSecurity实现WEB JWT认证

相信很多做技术的朋友都做过前后端分离项目,项目分离后认证就靠JWT,费话不多说,直接上干活(写的不好还请多多见谅,大牛请绕行)

直接上代码,项目为Maven项目,结构如图:

SpringBoot2.0整合SpringSecurity实现WEB JWT认证_第1张图片

包分类如下:

com.api.config  相关配置类

com.api.ctrl  controller层

com.api.entity  相关实体类

com.api.repo   jpa仓库相关

com.api.serice  service层相关

ApiApplication 为启动类

主要配置核心类如下:

JWTAuthenticationFilter 

package com.api.config;

import com.api.entity.User;
import com.api.repo.UserRepo;
import io.jsonwebtoken.Jwts;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;

public class JWTAuthenticationFilter extends BasicAuthenticationFilter {

    private UserRepo userRepo;

    public JWTAuthenticationFilter(AuthenticationManager authenticationManager,UserRepo userRepo) {
        super(authenticationManager);
        this.userRepo = userRepo;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {

        String header = request.getHeader("Authorization");
        //如果不包含Bearer则退出
        if(header != null && !header.startsWith("Bearer")){
            chain.doFilter(request,response);
            return;
        }

        UsernamePasswordAuthenticationToken authenticationToken = getAuthentication(request);
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        chain.doFilter(request,response);
    }

    private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
        String token = request.getHeader("Authorization");
        if (token != null) {
            // parse the token.
            String user = Jwts.parser()
                    .setSigningKey("HSMyJwtSecret".getBytes())
                    .parseClaimsJws(token.replace("Bearer ", ""))
                    .getBody()
                    .getSubject();
            if (user != null) {
                Integer userId = Integer.valueOf(user.split(":")[0]);
                User currUser = userRepo.findById(userId).orElse(null);
                if(currUser != null){
                    return new UsernamePasswordAuthenticationToken(currUser, null, new ArrayList<>());
                }
                return new UsernamePasswordAuthenticationToken(new User(), null, new ArrayList<>());
            }
        }
        return null;
    }
}
JWTLoginFilter
package com.api.config;

import com.api.entity.User;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;

public class JWTLoginFilter extends UsernamePasswordAuthenticationFilter {

    private AuthenticationManager authenticationManager;

    public JWTLoginFilter(AuthenticationManager authenticationManager){
        this.authenticationManager = authenticationManager;
    }

    
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        try {
            User user = new ObjectMapper().readValue(request.getInputStream(), User.class);
            return authenticationManager.authenticate(
              new UsernamePasswordAuthenticationToken(
                      user.getUsername(),
                      user.getPassword(),
                      new ArrayList<>()
              )
            );

        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }


    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        String token = Jwts.builder()
                .setSubject(((JwtUser) authResult.getPrincipal()).getUsername())
                .setExpiration(new Date(System.currentTimeMillis() + 60 * 60 * 24 * 1000))
                .signWith(SignatureAlgorithm.HS256,"HSMyJwtSecret".getBytes())
                .compact();
        response.addHeader("Authorization", "Bearer " + token);
        response.getOutputStream().println(token);
    }
}
MyUserDetailService
package com.api.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Component;

import java.util.Collection;

@Component
public class MyAuthencationProvider implements AuthenticationProvider {

    @Autowired
    private MyUserDetailService myUserDetailService;

    
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String username = authentication.getPrincipal().toString();
        JwtUser jwtUser = (JwtUser) myUserDetailService.loadUserByUsername(username);
        Collection authorities = jwtUser.getAuthorities();
        return new UsernamePasswordAuthenticationToken(jwtUser, jwtUser.getPassword(), authorities);
    }

    @Override
    public boolean supports(Class aClass) {
        return true;
    }
}
MyUserDetailService
package com.api.config;

import com.api.entity.User;
import com.api.repo.UserRepo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;

@Component
public class MyUserDetailService implements UserDetailsService {

    @Autowired
    private UserRepo userRepo;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        User user = userRepo.findFirstByUsername(s);
        if(user != null){
            JwtUser jwtUser = new JwtUser(String.format("%s:%s",String.valueOf(user.getId()),user.getUsername()),user.getPassword());
            return jwtUser;
        }
        throw new UsernameNotFoundException("用户名未找到");
    }
}


WebSecurityConfig
package com.api.config;

import com.api.repo.UserRepo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Order(-1)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyAuthencationProvider myAuthencationProvider;
    @Autowired
    private UserRepo userRepo;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and().csrf().disable().authorizeRequests()
                .antMatchers(HttpMethod.POST, "/register").permitAll()
                .anyRequest().authenticated()
                .and()
                .addFilter(new JWTLoginFilter(authenticationManager()))
                .addFilter(new JWTAuthenticationFilter(authenticationManager(),userRepo));
    }

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(myAuthencationProvider);
    }


}
JwtUser
package com.api.config;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.Collection;

public class JwtUser implements UserDetails {

    private String username;
    private String password;


    public JwtUser(String username,String password){
        this.username = username;
        this.password = password;
    }

    @Override
    public Collection getAuthorities() {
        return null;
    }

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

    @Override
    public String getUsername() {
        return username;
    }

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

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

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

    @Override
    public boolean isEnabled() {
        return false;
    }

}
MyMvcConfigurer
package com.api.config;

import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.SecurityConfig;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@AutoConfigureBefore(SecurityConfig.class)
public class MyMvcConfigurer implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedMethods("*")
                .allowedHeaders("*")
                .allowCredentials(true)
                .maxAge(3600);
    }
}

以上为config包下全部内容

SpringBoot2.0整合SpringSecurity实现WEB JWT认证_第2张图片

项目POM.xml配置如下



	4.0.0
	
		org.springframework.boot
		spring-boot-starter-parent
		2.1.0.RELEASE
		 
	
	com.api
	api
	0.0.1-SNAPSHOT
	api
	Demo project for Spring Boot

	
		1.8
	

	
		
			org.springframework.boot
			spring-boot-starter-data-redis
		
		
			org.springframework.boot
			spring-boot-starter-jdbc
		

		
			org.springframework.boot
			spring-boot-starter-data-jpa
		


		
			org.springframework.boot
			spring-boot-starter-security
		
		
			org.springframework.boot
			spring-boot-starter-web
		
		
			mysql
			mysql-connector-java
			runtime
		
		
			org.projectlombok
			lombok
			true
		

		
			org.springframework.boot
			spring-boot-starter-test
			test
		

		
			com.github.wenhao
			jpa-spec
			3.2.3
		

		
			cn.hutool
			hutool-all
			4.3.1
		

		
			io.jsonwebtoken
			jjwt
			0.7.0
		

	

	
		
			
				org.apache.maven.plugins
				maven-compiler-plugin
				3.5.1
				
					
						-verbose
						-Xlint:all,-options,-path
					
					1.8
					1.8
				
			

			
				org.springframework.boot
				spring-boot-maven-plugin
			
			
				maven-jar-plugin
				
					
						
							true
							lib/
							com.api.ApiApplication
						
					
				

			
			
				org.apache.maven.plugins
				maven-resources-plugin
				
					
						@
						#{*}
						#
					
				
			
		
	

	
		
			spring-snapshots
			Spring Snapshots
			https://repo.spring.io/snapshot
			
				true
			
		
		
			spring-milestones
			Spring Milestones
			https://repo.spring.io/milestone
		
	
	
		
			spring-snapshots
			Spring Snapshots
			https://repo.spring.io/snapshot
			
				true
			
		
		
			spring-milestones
			Spring Milestones
			https://repo.spring.io/milestone
		
	


以下为其他包结构以及类文件

SpringBoot2.0整合SpringSecurity实现WEB JWT认证_第3张图片

以上配置成功后即可以POST方式访问

http://localhost:8080/login?username=xxx&password=xx 认证成功后会在返回jwt,下次请求认证的资源在header里边带上Authorization Bearer xxxxxx
即可。

你可能感兴趣的:(SpringBoot)