zoukankan      html  css  js  c++  java
  • Spring Security整合Jwt

    本次基于Spring Boot整合了Spring SecurityJwt,可以解决前后端分离之后用户认证与授权的问题。在前后端还未分离的时候,对用户进行身份认证大约是这样的。



    客户端...


    服务端...
    用户登录
    用户登录
    登录成功,用户信息存储session
    登录成功,用户信息存储session
    返回登录状态,并发送cookie
    返回登录状态,并发送cookie
    将服务端发来的cookie存储
    将服务端发来的cookie存储
    携带cookie,发送请求
    携带cookie,发送请求
    Viewer does not support full SVG 1.1

    这种缺点就是身份信息需要客户端和服务器同时存储,当用户基数很大的时候,需要大量的内存来解决这个问题。

    在前后端分离之后,基于token的用户身份认证大约是这样的。



    客户端...


    服务端...
    用户登录
    用户登录
    登录成功,颁发token
    登录成功,颁发token
    将服务端发来的token存储
    将服务端发来的token存储
    携带token,发送请求
    携带token,发送请求
    Viewer does not support full SVG 1.1

    这种好处是token只需要存储到客户端,服务端只需要对发来的请求中验证token的有效性。

    本次便使用基于token的方式,结合spring security进行一次简单的身份认证与授权。

    相关版本信息

    名称 版本
    IDEA商业版 2020.1
    JDK JDK1.8
    Maven 3.5.4
    Windows 家庭版1903

    项目结构

    .
    ├── .idea
    ├── src
    │   └── main
    |       ├── java
    |       |   └── com
    |       |       └── example
    |       |           ├── controller
    |       |           |   └── HelloResource.java
    |       |           ├── filters
    |       |           |   └── JwtRequestFilter.java
    |       |           ├── model
    |       |           |   ├── AuthenticationRequest.java
    |       |           |   └── AuthenticationResponse.java
    |       |           ├── security
    |       |           |   ├── MyUserDetailsService.java
    |       |           |   └── SecurityConfigurer.java
    |       |           ├── utils
    |       |           |   └── JwtUtil.java     
    |       |           └── Application.java
    │       └── resources
    │           └── application.properties
    ├── test
    ├── target
    ├── pom.xml
    └── security-jwt.iml 
    

    在pom.xml添加相关jar包

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

    创建Application.java

    这个其实就是Spring Boot的入口文件,名称不一样也没事,内容也没有改动。

    package com.example;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class Application {
        public static void main(String[] args) {
            SpringApplication.run(Application.class, args);
        }
    }
    

    创建SecurityConfigurer.java

    这个类是Spring Security的配置类,Spring Boot提倡去掉配置文件,用配置类来代替,道理都差不多,我还是熟悉xml一些。

    package com.example.security;
    
    
    import com.example.filters.JwtRequestFilter;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.security.authentication.AuthenticationManager;
    import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
    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.config.http.SessionCreationPolicy;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
    
    @EnableWebSecurity
    public class SecurityConfigurer extends WebSecurityConfigurerAdapter {
    
        @Autowired
        private MyUserDetailsService myUserDetailsService;
    
        @Autowired
        JwtRequestFilter jwtRequestFilter;
    
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.userDetailsService(myUserDetailsService).passwordEncoder(bCryptpasswordEncoder());
        }
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.csrf().disable()
                    .authorizeRequests()
                    .antMatchers("/authenticate")
                    .permitAll()
                    .anyRequest()
                    .authenticated()
                    .and()
                    .sessionManagement()
                    .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
            http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
        }
    
        @Override
        @Bean
        public AuthenticationManager authenticationManagerBean() throws Exception {
            return super.authenticationManagerBean();
        }
    
        @Bean
        public BCryptPasswordEncoder bCryptpasswordEncoder() {
            return new BCryptPasswordEncoder();
        }
    }
    

    创建MyUserDetailsService.java

    这个类是通过传来用户的username,返回一个用户对象,这里为了简便没有从数据库进行查询,以后改成从数据库访问用户信息,直接在这里查询并返回一个用户就行了。

    这里密码采用了BCR加密。

    package com.example.security;
    
    import org.springframework.security.core.userdetails.User;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.core.userdetails.UsernameNotFoundException;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.stereotype.Service;
    
    import java.util.ArrayList;
    
    @Service
    public class MyUserDetailsService implements UserDetailsService {
        @Override
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
            return new User("foo",new BCryptPasswordEncoder().encode("foo"),new ArrayList<>());
        }
    }
    

    创建JwtUtil.java

    这个是Jwt的配置类,可以配置tokenSECRET_KEY,到期时间等等,更重要的作用是可以生成一个token

    package com.example.utils;
    
    import io.jsonwebtoken.Claims;
    import io.jsonwebtoken.Jwts;
    import io.jsonwebtoken.SignatureAlgorithm;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.stereotype.Component;
    
    import java.util.Date;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.function.Function;
    
    @Component
    public class JwtUtil {
    
        private String SECRET_KEY = "secret";
    
        public String extractUsername(String token){
            return extractClaim(token, Claims::getSubject);
        }
    
        public Date extractExpiration(String token){
            return extractClaim(token,Claims::getExpiration);
        }
    
        public <T> T extractClaim(String token, Function<Claims,T> claimsResolver){
            final Claims claims = extractAllClaims(token);
            return claimsResolver.apply(claims);
        }
    
        public Claims extractAllClaims(String token){
            return Jwts.parser()
                    .setSigningKey(SECRET_KEY)
                    .parseClaimsJws(token)
                    .getBody();
        }
    
        public Boolean isTokenExpired(String token){
            return extractExpiration(token).before(new Date());
        }
    
        public String generateToken(UserDetails userDetails){
            Map<String,Object> claims = new HashMap<>();
            return createToken(claims,userDetails.getUsername());
        }
    
        private String createToken(Map<String,Object> claims,String subject){
            return Jwts.builder()
                    .setClaims(claims)
                    .setSubject(subject)
                    .setIssuedAt(new Date(System.currentTimeMillis()))
                    .setExpiration(new Date(System.currentTimeMillis()+100*60*60*10))
                    .signWith(SignatureAlgorithm.HS256,SECRET_KEY)
                    .compact();
        }
        public Boolean validateToken(String token,UserDetails userDetails){
            final String username = extractUsername(token);
            return (username.equals(userDetails.getUsername())) && (!isTokenExpired(token));
        }
    
    }
    

    说明

    本文章原创自我的个人博客 https://srcrs.top ,如需要完整文章内容,以及源码,请访问:https://srcrs.top/posts/202007241.html ,迫不得已引流方式请勿介意。

  • 相关阅读:
    java之JDBC
    git删除未监视的文件
    java之正则表达式
    linux命令之信息显示与搜索文件命令
    linux命令之文件备份与压缩命令
    gitlab中修改项目名称客户端修改方法
    linux中使用unzip命令中文乱码解决办法
    使用Python进行统计量描述
    Machine Learning
    Courase Neural Networks for Machine Learning Lecture1 Note
  • 原文地址:https://www.cnblogs.com/sddr/p/13375144.html
Copyright © 2011-2022 走看看