Welcome WeChat search public number [Java version of Web project] for resources: Java learning video/design pattern notes/algorithm manual/Java project

What is Single Point Login

Single Sign On (SSO) is one of the most popular solutions for enterprise business integration. The definition of SSO is that in multiple applications, users only need to log in once to access all the mutually trusted applications

Two, simple operation mechanism

The single sign-on mechanism is actually relatively simple, let’s compare it with a real life example. There are many separate attractions within a certain park, and visitors can buy tickets at the entrance of each attraction separately. For tourists who need to play all the scenic spots, this way of buying tickets is very inconvenient. They need to queue up at the entrance of each scenic spot to buy tickets. The wallet is easy to lose and it is not safe to take it in. As a result, the vast majority of tourists choose to buy a single pass (also called a set of tickets) at the main gate, which allows them to visit all the scenic spots without having to buy a ticket again. All they need to do is show the set of tickets they bought at the entrance of each attraction and they are allowed to enter each individual attraction. The same is true for single sign-on, as shown in the figure below.

User authentication: This step is mainly for the user to make an authentication request to the authentication server, and the authentication server will return a successful token to the user, which is mainly completed in the authentication server, namely the authentication system in the figure. Note that there can only be one authentication system. Identity verification: When users carry tokens to visit other servers, the authenticity of tokens is checked in other servers, which is mainly completed in the resource server, that is, the application system 2 and 3 in the figure

3. Introduction to JWT

The concept that

From the distributed authentication process, it is not difficult to find that the token plays the most critical role. The security of token is directly related to the robustness of the system. Here we choose to use JWT to realize the generation and verification of token. JWT, JSON Web Token in full, https://jwt.io, is an excellent distributed authentication scheme. Tokens can be generated, and they can be parsed and verified.

The Token generated by JWT consists of three parts:

Header: mainly sets some specification information, the encoding format of the signature part is declared in the header. Load: The part of the token that stores valid information, such as user name, user role, expiration time, etc., but do not put the password, it will leak! Signature: After base64 encoding the header and payload respectively, use “. Connect them, add salt, and then code them using the type of code declared in the header, and you get a signature.

JWT generates token security analysis

From the composition of tokens generated by JWT, to avoid the token being forged, it mainly depends on the signature part. The signature part consists of three parts, in which the base64 encoding of the header and payload is almost transparent, with no security at all. In this way, the burden of protecting the token security finally falls on the salt added! Imagine if the same salt was used to create the token as was used to parse the token. Is it not similar to the People’s Bank of China to the renminbi anti-counterfeiting technology open? You can use this salt to resolve tokens, so you can use it to forge tokens. In this case, we need to encrypt the salt in an asymmetric way, so as to achieve the security effect that the generated token is inconsistent with the salt used by the verification token party!

Introduction to Asymmetric Encryption RSA

Basic principle: at the same time generate two keys: a private key and public key, private key secret, the public key can be send to trust the client private key encryption, holds the private key and public key can decrypt the public key encryption, holds the private key can decrypt the advantages: safety, hard to crack faults: algorithm is time-consuming, for the sake of safety, can accept history: Three mathematicians, Rivest, Shamir, and Adleman, have devised an algorithm that enables asymmetric encryption. The algorithm uses the three men’s initials: RSA.

SpringSecurity integration with JWT

1. Analysis of authentication ideas

SpringSecurity is primarily powered by filters! We need to find SpringSecurity’s filters for authenticating and verifying identities!

Review the centralized certification process

User authentication: AttemptAuthentication UsernamePasswordAuthenticationFilter a filter method is used to implement authentication function, the filter in the parent class successfulAuthentication method to achieve certification after a successful operation. Identity: doFilterInternal BasicAuthenticationFilter a filter method is used to verify the login, to decide whether to enter the subsequent filter.

Analyze the distributed authentication process

User authentication: Due to the distributed project, most of the architectural design, the separation of front and back side we are to meet acceptable asynchronous post authentication request parameters, the need to modify the UsernamePasswordAuthenticationFilter attemptAuthentication method in the filter, Enable it to receive the request body. In addition, the default SuccessfulAuthentication method puts the user information directly into the session once the authentication is passed. Now we need to modify this method to generate the token and return it to the user after the authentication is passed. Identity verification: Original doFilterInternal BasicAuthenticationFilter a filter method to check whether the user login, is to see if there is a user session information, we will modify for authenticating the user carry a token is legal, and parse out the user information, Give it to SpringSecurity so that subsequent authorization functions can be used normally.

2. Implementation

To demonstrate the effect of single sign-on, we designed the following project structure

2.1 Creation of the parent project

Since we need to create multiple systems in this case, we use the Maven aggregation project to do this. We first create a parent project and import the parent dependency of SpringBoot

<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> The < version > 2.1.3. RELEASE < / version > < relativePath / > < / parent > 123456

2.2 Establishment of public works

Then create a Common project, and other projects depend on this system



Import the JWT-related dependencies

<dependencies> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> < version > 0.10.7 < / version > < / dependency > < the dependency > < groupId >. IO jsonwebtoken < / groupId > <artifactId>jjwt-impl</artifactId> <version>0.10.7</version> <scope>runtime</scope> </dependency> <dependency> <dependency> < the groupId > IO. Jsonwebtoken < / groupId > < artifactId > JJWT - Jackson < / artifactId > < version > 0.10.7 < / version > <scope>runtime</scope> </dependency> <! - Jackson package - > < the dependency > < groupId > com. Fasterxml. Jackson. Core < / groupId > < artifactId > Jackson - databind < / artifactId > The < version > 2.9.9 < / version > < / dependency > <! > <dependency> < grouppid >org.springframework.boot</ grouppid > <artifactId>spring-boot-starter </artifactId> </dependency> <dependency> <groupId>joda-time</groupId> <artifactId>joda-time</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> </dependencies> 123456789101112131415161718192021222324252627282930313233343536373839404142

Create related utility classes

Payload

/** * @program: springboot-54-security-jwt-demo * @description: * @author: popo duck * @create: 2019-12-03 10:28 */ @Data public class Payload <T>{ private String id; private T userInfo; private Date expiration; } 123456789101112

JsonUtils

package com.dpb.utils; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.List; import java.util.Map; /** * @author: public class JsonUtills {public static final ObjectMapper = new ObjectMapper(); /** * @author: ObjectMapper(); private static final Logger logger = LoggerFactory.getLogger(JsonUtils.class); public static String toString(Object obj) { if (obj == null) { return null; } if (obj.getClass() == String.class) { return (String) obj; } try { return mapper.writeValueAsString(obj); } catch (JsonProcessingException e) {logger.error(" JSON serialization error: "+ obj, e); return null; } } public static <T> T toBean(String json, Class<T> tClass) { try { return mapper.readValue(json, tClass); } catch (ioException e) {logger.error(" + json: ", e); return null; } } public static <E> List<E> toList(String json, Class<E> eClass) { try { return mapper.readValue(json, mapper.getTypeFactory().constructCollectionType(List.class, eClass)); } catch (ioException e) {logger.error(" + json: ", e); return null; } } public static <K, V> Map<K, V> toMap(String json, Class<K> kClass, Class<V> vClass) { try { return mapper.readValue(json, mapper.getTypeFactory().constructMapType(Map.class, kClass, vClass)); } catch (ioException e) {logger.error(" + json: ", e); return null; } } public static <T> T nativeRead(String json, TypeReference<T> type) { try { return mapper.readValue(json, type); } catch (ioException e) {logger.error(" + json: ", e); return null; }}} 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646 566676869707172

JwtUtils

package com.dpb.utils; import com.dpb.domain.Payload; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jws; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import org.joda.time.DateTime; import java.security.PrivateKey; import java.security.PublicKey; import java.util.Base64; import java.util.UUID; /** * @author: Public class JwtUtils {private static final String JWT_PAYLOAD_USER_KEY = "user"; private static final String JWT_PAYLOAD_USER_KEY = "user"; /** * privateKey encrypt token ** @param userInfo load * @param privateKey privateKey * @param expire, Unit minutes * @ return JWT * / public static String generateTokenExpireInMinutes (Object the userInfo, PrivateKey PrivateKey, int expire) { return Jwts.builder() .claim(JWT_PAYLOAD_USER_KEY, JsonUtils.toString(userInfo)) .setId(createJTI()) .setExpiration(DateTime.now().plusMinutes(expire).toDate()) .signWith(privateKey, SignatureAlgorithm.RS256) .compact(); } /** * privateKey cryptographic token ** @Param userInfo load data * @Param privateKey privateKey * @Param expire, Unit s * @ return JWT * / public static String generateTokenExpireInSeconds (Object the userInfo, PrivateKey PrivateKey, int expire) { return Jwts.builder() .claim(JWT_PAYLOAD_USER_KEY, JsonUtils.toString(userInfo)) .setId(createJTI()) .setExpiration(DateTime.now().plusSeconds(expire).toDate()) .signWith(privateKey, SignatureAlgorithm.RS256) .compact(); } /** * publicKey resolve Token ** @Param publicKey publicKey * @Return Jws<Claims> */ private static Jws<Claims>  parserToken(String token, PublicKey publicKey) { return Jwts.parser().setSigningKey(publicKey).parseClaimsJws(token); } private static String createJTI() { return new String(Base64.getEncoder().encode(UUID.randomUUID().toString().getBytes())); } /** * Gets user information in the token ** @Param Token user request * @Param publicKey public key * @Return user information */ public static <T> Payload<T> getInfoFromToken(String token, PublicKey publicKey, Class<T> userType) { Jws<Claims> claimsJws = parserToken(token, publicKey); Claims body = claimsJws.getBody(); Payload<T> claims = new Payload<>(); claims.setId(body.getId()); claims.setUserInfo(JsonUtils.toBean(body.get(JWT_PAYLOAD_USER_KEY).toString(), userType)); claims.setExpiration(body.getExpiration()); return claims; } /** * Gets Payload information in the token ** @Param Token user request * @Param publicKey public key * @Return user information */ public static <T> Payload<T> getInfoFromToken(String token, PublicKey publicKey) { Jws<Claims> claimsJws = parserToken(token, publicKey); Claims body = claimsJws.getBody(); Payload<T> claims = new Payload<>(); claims.setId(body.getId()); claims.setExpiration(body.getExpiration()); return claims; }} 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646 566676869707172737475767778798081828384858687888990919293949596979899100101102103104

RsaUtils

package com.dpb.utils; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.security.*; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Base64; /** * @author */ public class RSautils {private static final int DEFAULT_KEY_SIZE = 2048; /** * Read the public key from the file ** @param filename public key save path, Classpath * @return public key object * @throws Exception */ public static PublicKey getPublicKey(String filename) throws Exception { byte[] bytes = readFile(filename); return getPublicKey(bytes); } /** * Read the key from the file ** @Param filename private key save path, Classpath * @return PrivateKey object * @throws Exception */ public static privateKey getPrivateKey(String filename) throws Exception { byte[] bytes = readFile(filename); return getPrivateKey(bytes); } /** * getPublicKey ** @Param Bytes * @Return * @throws Exception */ private static PublicKey getPublicKey(byte[] bytes) throws Exception { bytes = Base64.getDecoder().decode(bytes); X509EncodedKeySpec spec = new X509EncodedKeySpec(bytes); KeyFactory factory = KeyFactory.getInstance("RSA"); return factory.generatePublic(spec); } /** * getPrivateKey ** @Param bytes * @Return * @throws Exception */ private static privateKey getPrivateKey(byte[] bytes) throws NoSuchAlgorithmException, InvalidKeySpecException { bytes = Base64.getDecoder().decode(bytes); PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(bytes); KeyFactory factory = KeyFactory.getInstance("RSA"); return factory.generatePrivate(spec); } /** * According to the ciphertext, * * @Param publicKeyFilename public key file path * @Param privateKeyFilename private key file path * @Param secret generate key ciphertext */ public static void generateKey(String publicKeyFilename, String privateKeyFilename, String secret, int keySize) throws Exception { KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); SecureRandom secureRandom = new SecureRandom(secret.getBytes()); keyPairGenerator.initialize(Math.max(keySize, DEFAULT_KEY_SIZE), secureRandom); KeyPair keyPair = keyPairGenerator.genKeyPair(); // byte[] publicKeyBytes = keypair.getPublic ().getEncoded(); publicKeyBytes = Base64.getEncoder().encode(publicKeyBytes); writeFile(publicKeyFilename, publicKeyBytes); // byte[] privateKeyBytes = KeyPair.getPrivate ().getEncoded(); privateKeyBytes = Base64.getEncoder().encode(privateKeyBytes); writeFile(privateKeyFilename, privateKeyBytes); } private static byte[] readFile(String fileName) throws Exception { return Files.readAllBytes(new File(fileName).toPath()); } private static void writeFile(String destPath, byte[] bytes) throws IOException { File dest = new File(destPath); if (! dest.exists()) { dest.createNewFile(); } Files.write(dest.toPath(), bytes); }} 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646 566676869707172737475767778798081828384858687888990919293949596979899100101102103

Write the test class in the generic submodule to generate the RSA public key and private key

/** * @program: springboot-54-security-jwt-demo * @description: * @author: popo duck * @create: 2019-12-03 11:08 */ public class JwtTest { private String privateKey = "c:/tools/auth_key/id_key_rsa"; private String publicKey = "c:/tools/auth_key/id_key_rsa.pub"; @Test public void test1() throws Exception{ RsaUtils.generateKey(publicKey,privateKey,"dpb",1024); }} 1234567891011121314151617

2.3 Authentication system creation

Next we create our authentication service.

Import the associated dependencies

<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId>  </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> < artifactId > security - JWT - common < / artifactId > < groupId > com. The DPB < / groupId > < version > 1.0 - the SNAPSHOT < / version > < / dependency > < the dependency > < groupId > mysql < / groupId > < artifactId > mysql connector - Java < / artifactId > < version > 5.1.47 < / version > </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> < artifactId > mybatis - spring - the boot - starter < / artifactId > < version > 2.1.0 < / version > < / dependency > < the dependency > <group >com.alibaba</group > </artifactId> druid</artifactId> <version>1.1.10</version> </dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> </dependencies> 1234567891011121314151617181920212223242526272829303132333435

Creating configuration files

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/srm
    username: root
    password: 123456
    type: com.alibaba.druid.pool.DruidDataSource
mybatis:
  type-aliases-package: com.dpb.domain
  mapper-locations: classpath:mapper/*.xml
logging:
  level:
    com.dpb: debug
rsa:
  key:
    pubKeyFile: c:\tools\auth_key\id_key_rsa.pub
    priKeyFile: c:\tools\auth_key\id_key_rsa
1234567891011121314151617

Provides configuration classes for public and private keys

package com.dpb.config; import com.dpb.utils.RsaUtils; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; import javax.annotation.PostConstruct; import java.security.PrivateKey; import java.security.PublicKey; /** * @program: springboot-54-security-jwt-demo * @description: * @author: popo duck * @create: 2019-12-03 11:25 */ @Data @ConfigurationProperties(prefix = "rsa.key") public class RsaKeyProperties { private String pubKeyFile; private String priKeyFile; private PublicKey publicKey; private PrivateKey privateKey; Void createString () throws Exception {public void createString () throws Exception {public void createString () throws Exception {Publickey = RsaUtils.getPublicKey(pubKeyFile); privateKey = RsaUtils.getPrivateKey(priKeyFile); }} 1234567891011121314151617181920212223242526272829303132333435363738

Creating a startup class

/** * @Program: SpringBoot-54-Security-JWT-Demo * @Description: SpringBoot-54-Security-JWT-Demo * @Description: SpringBoot-54-Security-JWT-Demo * @Author: SpringBoot-54-Security * @Create: 2019-12-03 11:23 */ @SpringBootApplication @MapperScan("com.dpb.mapper") @EnableConfigurationProperties(RsaKeyProperties.class) public class App { public static void main(String[] args) { SpringApplication.run(App.class,args); }} 123456789101112131415

Complete the logic of data authentication

pojo

package com.dpb.domain; import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Data; import org.springframework.security.core.GrantedAuthority; /** * @program: springboot-54-security-jwt-demo * @description: * @author: popo duck * @create: 2019-12-03 15:21 */ @Data public class RolePojo implements GrantedAuthority { private Integer id; private String roleName; private String roleDesc; @JsonIgnore @Override public String getAuthority() { return roleName; } } 12345678910111213141516171819202122232425 package com.dpb.domain; import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Data; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import java.util.ArrayList; import java.util.Collection; import java.util.List; /** * @program: springboot-54-security-jwt-demo * @description: * @author: popo duck * @create: 2019-12-03 11:33 */ @Data public class UserPojo implements UserDetails { private Integer id; private String username; private String password; private Integer status; private List<RolePojo> roles; @JsonIgnore @Override public Collection<? extends GrantedAuthority> getAuthorities() { List<SimpleGrantedAuthority> auth = new ArrayList<>(); auth.add(new SimpleGrantedAuthority("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; }} 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646 566676869

Mapper interfaces

public interface UserMapper {
    public UserPojo queryByUserName(@Param("userName") String userName);
}
123

Mapper mapping file

<? The XML version = "1.0" encoding = "utf-8"? > <! DOCTYPE mapper PUBLIC "- / / mybatis.org//DTD mapper / 3.0 / EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > < mapper namespace="com.dpb.mapper.UserMapper"> <select id="queryByUserName" resultType="UserPojo"> select * from t_user where username = #{userName} </select> </mapper> 123456789

Service

public interface UserService extends UserDetailsService { } 123 @Service @Transactional public class UserServiceImpl implements UserService { @Autowired private UserMapper mapper; @Override public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException { UserPojo user = mapper.queryByUserName(s); return user; }} 1234567891011121314

Custom authentication filters

package com.dpb.filter; import com.dpb.config.RsaKeyProperties; import com.dpb.domain.RolePojo; import com.dpb.domain.UserPojo; import com.dpb.utils.JwtUtils; import com.fasterxml.jackson.databind.ObjectMapper; import net.bytebuddy.agent.builder.AgentBuilder; 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.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; 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.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @program: springboot-54-security-jwt-demo * @description: * @author: popo duck * @create: 2019-12-03 11:57 */ public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter { private AuthenticationManager authenticationManager; private RsaKeyProperties prop; public TokenLoginFilter(AuthenticationManager authenticationManager, RsaKeyProperties prop) { this.authenticationManager = authenticationManager; this.prop = prop; } public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { try { UserPojo sysUser = new ObjectMapper().readValue(request.getInputStream(), UserPojo.class); UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(sysUser.getUsername(), sysUser.getPassword()); return authenticationManager.authenticate(authRequest); }catch (Exception e){ 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 ", "wrong user name or password!" ); out.write(new ObjectMapper().writeValueAsString(resultMap)); out.flush(); out.close(); }catch (Exception outEx){ outEx.printStackTrace(); } throw new RuntimeException(e); } } public void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException { UserPojo user = new UserPojo(); user.setUsername(authResult.getName()); user.setRoles((List<RolePojo>)authResult.getAuthorities()); String token = JwtUtils.generateTokenExpireInMinutes(user, prop.getPrivateKey(), 24 * 60); response.addHeader("Authorization", "Bearer "+token); try { response.setContentType("application/json; charset=utf-8"); response.setStatus(HttpServletResponse.SC_OK); PrintWriter out = response.getWriter(); Map resultMap = new HashMap(); resultMap.put("code", HttpServletResponse.SC_OK); ResultMap.put (" MSG ", "authenticated!" ); out.write(new ObjectMapper().writeValueAsString(resultMap)); out.flush(); out.close(); }catch (Exception outEx){ outEx.printStackTrace(); }}} 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646 5666768697071727374757677787980818283848586878889

Customize the filter for validation tokens

package com.dpb.filter; import com.dpb.config.RsaKeyProperties; import com.dpb.domain.Payload; import com.dpb.domain.UserPojo; import com.dpb.utils.JwtUtils; import com.fasterxml.jackson.databind.ObjectMapper; 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.io.PrintWriter; import java.util.HashMap; import java.util.Map; /** * @program: springboot-54-security-jwt-demo * @description: * @author: popo duck * @create: 2019-12-03 12:39 */ public class TokenVerifyFilter extends BasicAuthenticationFilter { private RsaKeyProperties prop; public TokenVerifyFilter(AuthenticationManager authenticationManager, RsaKeyProperties prop) { super(authenticationManager); this.prop = prop; } public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { String header = request.getHeader("Authorization"); if (header == null || ! Header. startsWith("Bearer ")) {// If carrying the wrong token, give the user a hint Please login! 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 ", "Please login!" ); out.write(new ObjectMapper().writeValueAsString(resultMap)); out.flush(); out.close(); } else {// If carrying the correct format token get token String token = header.replace("Bearer ", ""); / / verify correct tken content < UserPojo > content = JwtUtils. GetInfoFromToken (token, prop getPublicKey (), UserPojo. Class); UserPojo user = payload.getUserInfo(); if(user! =null){ UsernamePasswordAuthenticationToken authResult = new UsernamePasswordAuthenticationToken(user.getUsername(), null, user.getAuthorities()); SecurityContextHolder.getContext().setAuthentication(authResult); chain.doFilter(request, response); }}}} 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364

### Write SpringSecurity configuration classes

package com.dpb.config; import com.dpb.filter.TokenLoginFilter; import com.dpb.filter.TokenVerifyFilter; import com.dpb.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; 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.config.http.SessionCreationPolicy; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; /** * @program: springboot-54-security-jwt-demo * @description: * @author: popo duck * @create: 2019-12-03 12:41 */ @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(securedEnabled=true) public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserService userService; @Autowired private RsaKeyProperties prop; @Bean public BCryptPasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } / / specify the source of the authentication object public void the configure (AuthenticationManagerBuilder auth) throws the Exception { auth.userDetailsService(userService).passwordEncoder(passwordEncoder()); } public void Configure (HttpSecurity) throws Exception {http.csrf().disable(); .authorizeRequests() .antMatchers("/user/query").hasAnyRole("ADMIN") .anyRequest() .authenticated() .and() .addFilter(new TokenLoginFilter(super.authenticationManager(), prop)) .addFilter(new TokenVerifyFilter(super.authenticationManager(), prop)) .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); }} 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556

Start service testing

Start the service

Access tests through PostMan

We access other resources based on token information

2.4 Resource system creation

Note that there can be many resource services. Take a product service as an example, and remember that the resource service can only be authenticated with a public key. Token cannot be issued! Create the product service and import the JAR package according to the actual business guide package, we will be the same as the authentication service for the time being.

Next we create a resource service

Import the associated dependencies

<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId>  </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> < artifactId > security - JWT - common < / artifactId > < groupId > com. The DPB < / groupId > < version > 1.0 - the SNAPSHOT < / version > < / dependency > < the dependency > < groupId > mysql < / groupId > < artifactId > mysql connector - Java < / artifactId > < version > 5.1.47 < / version > </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> < artifactId > mybatis - spring - the boot - starter < / artifactId > < version > 2.1.0 < / version > < / dependency > < the dependency > <group >com.alibaba</group > </artifactId> druid</artifactId> <version>1.1.10</version> </dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> </dependencies> 1234567891011121314151617181920212223242526272829303132333435

Write product service configuration files

Remember you can only have public key addresses here!

server:
  port: 9002
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/srm
    username: root
    password: 123456
    type: com.alibaba.druid.pool.DruidDataSource
mybatis:
  type-aliases-package: com.dpb.domain
  mapper-locations: classpath:mapper/*.xml
logging:
  level:
    com.dpb: debug
rsa:
  key:
    pubKeyFile: c:\tools\auth_key\id_key_rsa.pub
123456789101112131415161718

Write a configuration class that reads the public key

package com.dpb.config; import com.dpb.utils.RsaUtils; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import javax.annotation.PostConstruct; import java.security.PrivateKey; import java.security.PublicKey; /** * @program: springboot-54-security-jwt-demo * @description: * @author: popo duck * @create: 2019-12-03 11:25 */ @Data @ConfigurationProperties(prefix = "rsa.key") public class RsaKeyProperties { private String pubKeyFile; private PublicKey publicKey; Void createString () throws Exception {public void createString () throws Exception {public void createString () throws Exception {Publickey = RsaUtils.getPublicKey(pubKeyFile); }} 12345678910111213141516171819202122232425262728293031323334

Writing the boot class

package com.dpb; import com.dpb.config.RsaKeyProperties; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.context.properties.EnableConfigurationProperties; /** * @program: springboot-54-security-jwt-demo * @description: * @author: popo duck * @create: 2019-12-03 17:23 */ @SpringBootApplication @MapperScan("com.dpb.mapper") @EnableConfigurationProperties(RsaKeyProperties.class) public class App { public static void main(String[] args) { SpringApplication.run(App.class,args); }} 1234567891011121314151617181920212223

Copy the interface of the user object, role object, and verification authentication in the authentication service

Copy the relevant content from the authentication service

Copy the SpringSecurity configuration class from the authentication service to make the changes

package com.dpb.config; import com.dpb.filter.TokenVerifyFilter; import com.dpb.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; 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.config.http.SessionCreationPolicy; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; /** * @program: springboot-54-security-jwt-demo * @description: * @author: popo duck * @create: 2019-12-03 12:41 */ @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(securedEnabled=true) public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserService userService; @Autowired private RsaKeyProperties prop; @Bean public BCryptPasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } / / specify the source of the authentication object public void the configure (AuthenticationManagerBuilder auth) throws the Exception { auth.userDetailsService(userService).passwordEncoder(passwordEncoder()); } public void Configure (HttpSecurity) throws Exception {http.csrf().disable(); .authorizeRequests() //.antMatchers("/user/query").hasAnyRole("USER") .anyRequest() .authenticated() .and() .addFilter(new TokenVerifyFilter(super.authenticationManager(), Prop)) / / disabled session. SessionManagement () sessionCreationPolicy (sessionCreationPolicy. STATELESS); }} 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556

Remove “add custom authentication filter”!

Writing a product processor

package com.dpb.controller; import org.springframework.security.access.annotation.Secured; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * @program: springboot-54-security-jwt-demo * @description: * @author: popo duck * @create: 2019-12-03 11:55 */ @RestController @RequestMapping("/user") public class UserController { @RequestMapping("/query") public String query(){ return "success"; } @RequestMapping("/update") public String update(){ return "update"; }} 1234567891011121314151617181920212223242526

test

Do ~

Author: Bobo Duck


Source:
https://blog.csdn.net/qq_3852…

SpringCloud micro-service e-commerce project tutorial