Rumah  >  Artikel  >  Java  >  Cara menggunakan SpringBoot+SpringSecurity+jwt untuk melaksanakan pengesahan

Cara menggunakan SpringBoot+SpringSecurity+jwt untuk melaksanakan pengesahan

WBOY
WBOYke hadapan
2023-05-24 20:07:131589semak imbas

Persekitaran

  • springBoot 2.3.3

  • springSecurity 5.0

  • 9

    1 jwt >

Maklumat utama fail Pox.xml

        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>
        <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>

Maklumat struktur direktori

Sila abaikan penamaan fail

Cara menggunakan SpringBoot+SpringSecurity+jwt untuk melaksanakan pengesahan

jwtAccessDeniedHandler dan JwtAuthenticationEntryPoint

Fungsi kedua-dua kelas ini adalah untuk pengguna mengakses sumber yang tidak dibenarkan dan kelas maklumat pemprosesan pengembalian ralat yang membawa token ralat ini hanya perlu Konfigurasikan sahaja dalam fail konfigurasi keselamatan dan hanya gunakan

/**
 * @author Bxsheng
 * @blogAddress www.kdream.cn
 * @createTIme 2020/9/17
 * since JDK 1.8
 * 当用户在没有授权的时候,返回的指定信息
 */
@Component
public class jwtAccessDeniedHandler implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
        System.out.println("用户访问没有授权资源");
        System.out.println(e.getMessage());
        httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, e==null?"用户访问没有授权资源":e.getMessage());

    }
}
/**
 * @author Bxsheng
 * @blogAddress www.kdream.cn
 * @createTIme 2020/9/17
 * since JDK 1.8
 */
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
        System.out.println("用户访问资源没有携带正确的token");
        System.out.println(e.getMessage());
        httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, e==null?"用户访问资源没有携带正确的token":e.getMessage());

    }
}

UserDetailsServiceImpl untuk pengesahan maklumat log masuk

Kelas ini secara langsung mewarisi UserDetailsService untuk pengesahan maklumat log masuk dan masukkan kata laluan akaun Apabila log masuk, kelas ini akan dimasukkan untuk mengesahkan maklumat.

Sudah tentu, saya terus menggunakan kata laluan berkod keras di sini Biasanya, maklumat pengguna dan maklumat kebenaran harus diperolehi daripada pangkalan data

@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {

        //直接写死数据信息,可以在这里获取数据库的信息并进行验证

        UserDetails userDetails  = User.withUsername(s).password(new BCryptPasswordEncoder().encode("123456"))
                .authorities("bxsheng").build();
        return userDetails;
    }
}

kelas pembungkusan JwtTokenUtils

.

Kelas ini secara langsung menggunakan kelas dalam artikel slyh [SpringBoot+JWT untuk melaksanakan kawalan kebenaran log masuk (kod))]((https://www.yisu.com/article/257119.htm).

package cn.kdream.securityjwt.utlis;

import io.jsonwebtoken.*;

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

/**
 * @author Bxsheng
 * @blogAddress www.kdream.cn
 * @createTIme 2020/9/16
 * since JDK 1.8
 */
public class JwtTokenUtils {
    public static final String TOKEN_HEADER = "Authorization";
    public static final String TOKEN_PREFIX = "Bearer ";
    public static final String SECRET = "jwtsecret";
    public static final String ISS = "echisan";

    private static final Long EXPIRATION = 60 * 60 * 3L; //过期时间3小时

    private static final String ROLE = "role";

    //创建token
    public static String createToken(String username, String role, boolean isRememberMe){
        Map map = new HashMap();
        map.put(ROLE, role);
        return Jwts.builder()
                .signWith(SignatureAlgorithm.HS512, SECRET)
                .setClaims(map)
                .setIssuer(ISS)
                .setSubject(username)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION * 1000))
                .compact();
    }

    //从token中获取用户名(此处的token是指去掉前缀之后的)
    public static String getUserName(String token){
        String username;
        try {
            username = getTokenBody(token).getSubject();
        } catch (    Exception e){
            username = null;
        }
        return username;
    }

    public static String getUserRole(String token){
        return (String) getTokenBody(token).get(ROLE);
    }

    private static Claims getTokenBody(String token){
        Claims claims = null;
        try{
            claims = Jwts.parser().setSigningKey(SECRET).parseClaimsJws(token).getBody();
        } catch(ExpiredJwtException e){
            e.printStackTrace();
        } catch(UnsupportedJwtException e){
            e.printStackTrace();
        } catch(MalformedJwtException e){
            e.printStackTrace();
        } catch(SignatureException e){
            e.printStackTrace();
        } catch(IllegalArgumentException e){
            e.printStackTrace();
        }
        return claims;
    }

    //是否已过期
    public static boolean isExpiration(String token){
        try{
            return getTokenBody(token).getExpiration().before(new Date());
        } catch(Exception e){
            System.out.println(e.getMessage());
        }
        return true;
    }
}

JwtAuthenticationFilter Pengesahan tersuai jwt

Kelas ini secara langsung menggunakan slyh [SpringBoot+JWT untuk melaksanakan kawalan kebenaran log masuk (kod))](( https://www. yisu.com /article/257119.htm))) kelas dalam artikel.

Fungsi utama kelas ini adalah untuk mengesahkan maklumat jwt terutamanya membawa permintaan token, menghuraikan jwt dan menetapkannya dalam konteks keselamatan. Menyimpan maklumat kebenaran yang terkandung dalam token kepada konteks adalah salah satu tujuan pendekatan ini. Anda boleh mengesahkan pengguna

/**
 * @author Bxsheng
 * @blogAddress www.kdream.cn
 * @createTIme 2020/9/16
 * since JDK 1.8
 */
public class JwtAuthenticationFilter extends BasicAuthenticationFilter {

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

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        String tokenHeader = request.getHeader(JwtTokenUtils.TOKEN_HEADER);
        //如果请求头中没有Authorization信息则直接放行了
        if(tokenHeader == null || !tokenHeader.startsWith(JwtTokenUtils.TOKEN_PREFIX)){
            chain.doFilter(request, response);
            return;
        }
        //如果请求头中有token,则进行解析,并且设置认证信息
        if(!JwtTokenUtils.isExpiration(tokenHeader.replace(JwtTokenUtils.TOKEN_PREFIX,""))){
            //设置上下文
            UsernamePasswordAuthenticationToken authentication = getAuthentication(tokenHeader);
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }
        super.doFilterInternal(request, response, chain);
    }

    //获取用户信息
    private UsernamePasswordAuthenticationToken getAuthentication(String tokenHeader){
        String token = tokenHeader.replace(JwtTokenUtils.TOKEN_PREFIX, "");
        String username = JwtTokenUtils.getUserName(token);
        // 获得权限 添加到权限上去
        String role = JwtTokenUtils.getUserRole(token);
        List<GrantedAuthority> roles = new ArrayList<GrantedAuthority>();
        roles.add(new GrantedAuthority() {
            @Override
            public String getAuthority() {
                return role;
            }
        });
        if(username != null){
            return new UsernamePasswordAuthenticationToken(username, null,roles);
        }
        return null;
    }

}

maklumat konfigurasi keselamatan

@EnableGlobalMethodSecurity(prePostEnabled = true) Dayakan kebenaran anotasi prePostEnabled

kelas r

🎜>

Saya mengkonfigurasi tiga kaedah dalam kelas permulaan, satu digunakan untuk memberikan maklumat log masuk dan dua lagi ditetapkan untuk memerlukan akses kebenaran

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityJwtConfig extends WebSecurityConfigurerAdapter {


    @Autowired
    private jwtAccessDeniedHandler jwtAccessDeniedHandler;

    @Autowired
    private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
       http.cors().and().csrf().disable().authorizeRequests()
               .antMatchers(HttpMethod.OPTIONS,"/**")
               .permitAll()
               .antMatchers("/").permitAll()
               //login 不拦截
               .antMatchers("/login").permitAll()
               .anyRequest().authenticated()
               //授权
               .and()
               // 禁用session
               .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
       // 使用自己定义的拦截机制,拦截jwt
        http.addFilterBefore(new JwtAuthenticationFilter(authenticationManager()), UsernamePasswordAuthenticationFilter.class)
        //授权错误信息处理
                .exceptionHandling()
                //用户访问资源没有携带正确的token
                .authenticationEntryPoint(jwtAuthenticationEntryPoint)
                //用户访问没有授权资源
                .accessDeniedHandler(jwtAccessDeniedHandler);
    }

    @Bean
    public PasswordEncoder passwordEncoder(){
        //使用的密码比较方式
        return  new BCryptPasswordEncoder();
    }

}

Kesan

Akses terus kepada maklumat pengguna yang memerlukan kebenaran

Akses terus kepada maklumat sumber yang hanya memerlukan kebenaran tanpa menggunakan token akan memasuki kelas JwtAuthenticationEntryPoint

Cara menggunakan SpringBoot+SpringSecurity+jwt untuk melaksanakan pengesahan

Dapatkan token

Akses kaedah log masuk dalam kelas permulaan dan dapatkan maklumat token

Oleh kerana saya menggunakan kata laluan tetap, saya gunakan Apabila mengakses dengan kata laluan yang salah , anda boleh menangkap maklumat pengecualian dalam pengendalian pengecualian global springboot

@SpringBootApplication
@RestController
public class SecurityJwtApplication {

    private final AuthenticationManagerBuilder authenticationManagerBuilder;

    public SecurityJwtApplication(AuthenticationManagerBuilder authenticationManagerBuilder) {
        this.authenticationManagerBuilder = authenticationManagerBuilder;
    }

    public static void main(String[] args) {
        SpringApplication.run(SecurityJwtApplication.class, args);
    }



    @GetMapping("/")
    public String index(){
        return "security jwt";
    }

    @PostMapping("/login")
    public String login(@RequestParam String u,@RequestParam String p){
        // 登陆验证
        UsernamePasswordAuthenticationToken token =
                new UsernamePasswordAuthenticationToken(u, p);
        Authentication authentication = authenticationManagerBuilder.getObject().authenticate(token);
        SecurityContextHolder.getContext().setAuthentication(authentication);
        //创建jwt信息
        String token1 = JwtTokenUtils.createToken(u,"bxsheng", true);
        return token1;
    }

    @GetMapping("/role")
    @PreAuthorize("hasAnyAuthority(&#39;bxsheng&#39;)")
    public String roleInfo(){
        return "需要获得bxsheng权限,才可以访问";
    }

    @GetMapping("/roles")
    @PreAuthorize("hasAnyAuthority(&#39;kdream&#39;)")
    public String rolekdream(){
        return "需要获得kdream权限,才可以访问";
    }
}

Cara menggunakan SpringBoot+SpringSecurity+jwt untuk melaksanakan pengesahan

Dapatkan token dengan betul dan akses sumber yang dilindungi

mengandungi hard -berkod maklumat kebenaran bxsheng, jadi anda biasanya boleh mendapatkan maklumat sumber yang dikenal pasti oleh bxsheng.

Cara menggunakan SpringBoot+SpringSecurity+jwt untuk melaksanakan pengesahan

Berjaya memperoleh maklumat

Cara menggunakan SpringBoot+SpringSecurity+jwt untuk melaksanakan pengesahan

Mencuba mendapatkan maklumat sumber yang tidak dibenarkan

Menggunakan token untuk mengakses terus maklumat sumber yang tidak dibenarkan akan memasuki kelas jwtAccessDeniedHandler

Cara menggunakan SpringBoot+SpringSecurity+jwt untuk melaksanakan pengesahan

Atas ialah kandungan terperinci Cara menggunakan SpringBoot+SpringSecurity+jwt untuk melaksanakan pengesahan. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:yisu.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam