Blog homepage: me.csdn.net/u010974701
Source code repository: github.com/zhshuixian/…
In the previous section of Spring Boot 2.X Real Life –Spring Security Login and Registration, we mainly integrated Spring Security to achieve user registration, login, and permission control.
In this section, we will implement Token based secure access control for Web applications. Token is a stateless authentication method that does not retain user authentication information on the server like a Session does, making it ideal for RESTful apis.
For Web applications with pure Token authentication, the general idea is as follows: Based on the previous project, disable the Session provided by Spring Security to allow cross-domain requests. Add a Token interceptor that intercepts all requests and verifies that the Token is valid.
If you want to implement Session + Token, my idea is to add Session and Token interceptors and also block all requests. Requests with cookies are authenticated and authorized by Session; The Token interceptor authenticates and authorizes the Token without Cookie. (This idea has not been practiced, hee hee, if you can welcome the message to tell small first).
In this section, instead of using MVC pattern, MySQL and MyBatis are used to build RESTful API implementation.
1) What is Token
1.1) How does the server know if the user is logged in
As we know, the HTTP protocol itself does not include state. Every time the client-server HTTP communication ends, it is disconnected, so HTTP does not remember who the logged-in user is.
To solve the problem that each request requires a user name and password for user authentication, the following two methods are generally used. The two methods have their own advantages and disadvantages, and can be selected according to the actual situation of the project.
Session-based authentication
1. After the user logs in, the server generates the user’s login information (Session) and returns the ID of the login information (Session_ID) to the client. The client saves the data through cookies.
2. The client only needs to search for the corresponding login information (Session) on the server with the login ID (Session_ID) for each request.
3. If the login information (Session) is found, the authentication is passed.
This is not a problem for a single service application if it is scaled to a distributed application. For example, A company has two services, A and B, and users can access the two services after logging in to either service. The implementation idea is to make the Session persistent, such as writing into the database or Redis cache, going to the database or Redis cache to find the Session during verification, periodically cleaning the database or setting the Redis expiration time.
Token-based authentication method
In this method, the user’s login information is not saved on the server, but the user’s Token is saved on the client. The client requests the Token and the server verifies the validity of the Token.
1. The user enters the user name and password and encrypts the password to generate a Token
2. The client saves the Token and carries it with it each time it requests
3. The server verifies the validity of the Token based on the key
If services A and B use the same encryption algorithm and key, the Token generated by one service can be directly used by the other service. Even if A new C service is added, the Token of the three services is universal as long as the encryption algorithm and key are the same.
To invalidate an unexpired Token after a user changes the password, you can add a timestamp to the user table. As long as the Token is generated before the timestamp, it will be invalid by default. Another method is to add a Redis cache and delete the user’s Token cache after changing the user’s information. If no user’s Token in the cache is directly invalid by default.
For the method of configuring single sign-on, my current thinking is still only Redis cache (manual face mask).
1.2) What does Token look like?
The Token consists of three parts
- Header
- Payload
- Signature (= Signature)
Complete Token example with three parts separated by decimal point. :
eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJTcHJpbmdCb290IiwiYXVkIjoiYm9vdCIsImV4cCI6MTU4NjE5MzMwMywiaWF0IjoxNTg1NTg4NTAzLCJyb2xlIjo iQURNSU4ifQ.SdHSoet9BEaMcBrbbwO4_nd88nO7VIuV6IB_Kdw1AFmmPPCxY8CKUoE-QrJmN3RSMAdxLB0GAfDiwFV6zpxVZksXZQAQzxa_bPw0JUj7mZyHzdSR2jNm_o KB_2rnRsfW7caXZVgwtUU2lHoXSLdlgHRqoyIw7AcP5dm-og3ELGgUQxa27mmwvXtRngfvgw1EKoeA_bdwNSbDWu8clyNjd9ftq9_yU3QKFc3NAUVkWTRa8U 1_dyOI9B4LMrKrXEQSR8D7UDw-0MDbOZNwzUmxv0h-QER1cw5dxnQsMs2C9TI32x9E68PaNC8PkaAyOkCs55y-W7wyf-K24fzt5nQb4wCopy the code
Note that headers and payloads are not encrypted and are encoded in JSON format by Bas64 algorithm, so passwords and user privacy information cannot be stored in Token.
The Header in the head
{
"alg": "HS256"
}
Copy the code
The header is the encryption algorithm that declares the Signature of the Token. The first part of the Token is obtained after Base64 encoding, as shown in the following example:
eyJhbGciOiJIUzI1NiJ9
Copy the code
Payload
{
"sub": "Joe"
}
Copy the code
This is the main part of the Token. Here is also the second part of the Token after Base64 encoding, as shown in the following example:
eyJzdWIiOiJKb2UifQ.1KP0SsvENi7Uz1oQc07aXTL7kpQG5jBNIybqr60AlD4
Copy the code
Note that the Payload is not encrypted. Do not store any private information, such as passwords and user privacy information.
Standard Claims commonly used Settings are as follows:
setIssuer
: The issuer of the TokensetSubject
Theme: the TokensetAudience
: Token recipientsetExpiration
: Expiration timesetNotBefore
: After what date does it become effectivesetIssuedAt
: Issue timesetId
: Unique identifier
Custom Claims:
.claim("role", "ADMIN")
: Uses this method to define a claim named role with the value ADMIN
Signature (= Signature)
The signature part is generated by encrypting the Header and Payload of the Token based on the encryption mode declared in the Header and the key defined by the server. If the data in the Header and Payload changes, the signature part is generated by encrypting the Header and Payload of the Token based on the encryption mode declared in the Header and the key defined by the server. The Signature then changes, and no one else can tamper with or forge the Token without revealing the key, which is why the Token is secure.
SdHSoet9BEaMcBrbbwO4_nd88nO7VIuV6IB_Kdw1AFmmPPCxY8CKUoE-QrJmN3RSMAdxLB0GAfDiwFV6zpxVZksXZQAQzxa_bPw0JUj7mZyHzdSR2jNm_oKB _2rnRsfW7caXZVgwtUU2lHoXSLdlgHRqoyIw7AcP5dm-og3ELGgUQxa27mmwvXtRngfvgw1EKoeA_bdwNSbDWu8clyNjd9ftq9_yU3QKFc3NAUVkWTRa8U1_ dyOI9B4LMrKrXEQSR8D7UDw-0MDbOZNwzUmxv0h-QER1cw5dxnQsMs2C9TI32x9E68PaNC8PkaAyOkCs55y-W7wyf-K24fzt5nQb4wCopy the code
JJWT is an open source (Apache 2.0) toolkit for creating and validating JSON Web Tokens (JWT) on the JVM and Android. It is a Java implementation based on the JWT, JWS, JWE, JWK specifications. Supported encryption algorithms include HMAC, RSASSA, and ECDSA. During development, a key strong enough for the selected algorithm must be used. In this section, RSA asymmetric encryption is used to encrypt tokens.
2) JJWT dependency import and project configuration
Create item 06-security-token, note that the Spring Boot version must be 2.1.X, remember to check Spring Security, MySQL, MyBatis, Web dependency.
For Maven projects, the corresponding dependency configuration is also given at the end of the article.
Gradle project configuration
implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org. Mybatis. Spring. The boot: mybatis - spring - the boot - starter: 2.1.2' runtimeOnly 'mysql: mysql connector - Java testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org. Springframework. Security: spring ws-security - test' / / add the following dependence on https://github.com/jwtk/jjwt the compile 'IO. Jsonwebtoken: JJWT - API: 0.11.1' runtime 'IO. Jsonwebtoken: JJWT - impl: 0.11.1', // Uncomment the next line if you want to use RSASSA-PSS (PS256, PS384, PS512) algorithms: / / 'org. Bouncycastle: bcprov - jdk15on: 1.60', // or 'IO. Jsonwebtoken :jjwt-gson:0.11.1' for gson' IO. Jsonwebtoken :jjwt-jackson:0.11.1'Copy the code
1.2) Project configuration
Configure the MySQL database and MyBatis camel name conversion, application.properties
You only need to change the database URL, username, password, and JDBC Driver
MySQL 8 needs to specify serverTimezone to connect to MySQLspring.datasource.url=jdbc:mysql://localhost:3306/spring? useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
spring.datasource.password=xiaoxian
spring.datasource.username=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# MyBatis Hump naming conversion
mybatis.configuration.map-underscore-to-camel-case=true
Copy the code
Add @ MapperScan
@MapperScan("org.xian.security.mapper")
public class SecurityApplication {}
Copy the code
2) Start using JJWT
Main structure of the project:
- Controller package: API interface
- Service package: Provides interface services for apis
- Mapper package: MyBatis Mapper class
- Entity package: Entity class
- Security package: Token interception validation, Token generation, Spring Security configuration
MyResponse: public Response returns a message class:
public class MyResponse implements Serializable {
private static final long serialVersionUID = -2L;
private String status;
private String message;
}
Copy the code
2.1) Entity classes Entity and Mapper
The table structure here is the same as in the previous section, with the user table SYS_user
field | type | note |
---|---|---|
user_id | bigint | Since the primary key |
username | varchar(18) | User name, not null unique |
password | varchar(60) | Password, not empty |
user_role | varchar(8) | USER Role (USER/ADMIN) |
The USER role is USER/ADMIN. The case that a USER may have multiple roles is not considered.
SQL
use spring;
create table sys_user
(
user_id bigint auto_increment,
username varchar(18) not null unique,
password varchar(60) not null,
user_role varchar(8) not null,
constraint sys_user_pk
primary key (user_id)
);
Copy the code
Entity Entity class: Create a package with the name Entity. Create a new SysUser class under Entity:
public class SysUser implements Serializable {
private static final long serialVersionUID = 4522943071576672084L;
private Long userId;
private String username;
private String password;
private String userRole;
// omit getter setter constructor
}
Copy the code
Mapper interface class: Create a package Mapper, create a SysUserMapper class:
// Use annotations here
public interface SysUserMapper {
/** Insert a record * to sys_user@paramSysUser User information */
@Insert("Insert Into sys_user(username, password,user_role) Values(#{username}, #{password},#{userRole})")
@Options(useGeneratedKeys = true, keyProperty = "userId")
void insert(SysUser sysUser);
/** Query user information based on Username *@paramUsername username *@returnUser information */
@Select("Select user_id,username, password,user_role From sys_user Where username=#{username}")
SysUser selectByUsername(String username);
}
Copy the code
2.2) Token configuration
Such as the following parts
- RSA key Public key tool class
- Token generation and validation tool classes
- Token interceptor that intercepts all requests and verifies that the Token is valid
- Custom unauthorized access error handling classes
- User-defined implementation of UserDetailsService interface
- Spring Security configuration
Under the Security package, create the RsaUtils class, the utility class for RSA public keys and keys. Note that in JDK 8, 2048-bit keys are not supported.
public class RsaUtils {
Openssl genrsa -out rsa_private_key.pem 2048 * Convert to PKCS8 format >openssl pkCS8-topk8-inform * pem Pem -outform pem -nocrypt * Delete -----BEGIN PRIVATE KEY----- * -----END PRIVATE KEY----- * when the terminal outputs the result@return PrivateKey
*/
public static PrivateKey getPrivateKey(a) {
PrivateKey privateKey = null;
try {
String privateKeyStr = "PrivateKey";
// Key in PKCS8 format
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKeyStr));
/ / the RSA algorithm
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePrivate(keySpec);
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
e.printStackTrace();
}
return privateKey;
}
Openssl rsa -in rsa_private_key.pem -out rsa_public_key.pem -pubout *@return PublicKey
*/
public static PublicKey getPublicKey(a) {
PublicKey publicKey = null;
try {
String publicKeyStr = "public key";
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(publicKeyStr));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePublic(keySpec);
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
e.printStackTrace();
return null; }}}Copy the code
TokenUtils: Utility class that generates and validates tokens. The optional Token body part means that this information is not used for authentication and authorization:
@Component
public class TokenUtils implements Serializable {
private static final long serialVersionUID = -3L;
/** * Token validity period */
private static final Long EXPIRATION = 604800L;
/** The Token string must be generated setAudience Receiver setExpiration time role User role *@paramSysUser User information *@returnGenerated Token string or NULL */
public String createToken(SysUser sysUser) {
try {
// Expiration time of Token
Date expirationDate = new Date(System.currentTimeMillis() + EXPIRATION * 1000);
/ / Token is generated
String token = Jwts.builder()
// Set Token issuer optional
.setIssuer("SpringBoot")
// Set the Token receiver based on the user name
.setAudience(sysUser.getUsername())
// Set the expiration time
.setExpiration(expirationDate)
// Setting the Token generation time Optional
.setIssuedAt(new Date())
// Use the claim method to set a key = role, value = userRole value
.claim("role", sysUser.getUserRole())
// Set the encryption key and algorithm. Use the private key for encryption and ensure that the private key is not leaked
.signWith(RsaUtils.getPrivateKey(), SignatureAlgorithm.RS256)
.compact();
return String.format("Bearer %s", token);
} catch (Exception e) {
return null; }}/** Verify the Token and obtain the user name and user permission information *@paramToken Token character string *@returnSysUser User information */
public SysUser validationToken(String token) {
try {
// Decrypts the Token to obtain the Claims body
Claims claims = Jwts.parserBuilder()
// Set public key decryption, assuming that the private key is private, so that the Token can only be generated by itself, thus verifying the Token
.setSigningKey(RsaUtils.getPublicKey())
.build().parseClaimsJws(token).getBody();
assertclaims ! =null;
// Verify whether the Token has expired
Date expiration = claims.getExpiration();
The expiration time must be after the current date
if(! expiration.after(new Date())) {
return null;
}
SysUser sysUser = new SysUser();
sysUser.setUsername(claims.getAudience());
sysUser.setUserRole(claims.get("role").toString());
return sysUser;
} catch (Exception e) {
e.printStackTrace();
return null; }}}Copy the code
TokenFilter: Token interceptor that intercepts all requests and verifies whether the Token is valid. If the request is valid, the authorization is approved. If the request is invalid, Spring Security intercepts the invalid request according to the configuration:
@SuppressWarnings("SpringJavaAutowiringInspection")
@Service
public class TokenFilter extends OncePerRequestFilter {
@Resource
TokenUtils tokenUtils;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
// Stores the Headers Key and Value of the Token. The default Value is Authorization
final String authorizationKey = "Authorization";
String authorizationValue;
try {
authorizationValue = request.getHeader(authorizationKey);
} catch (Exception e) {
authorizationValue = null;
}
// Token opening partial default Bearer opening
String bearer = "Bearer ";
if(authorizationValue ! =null && authorizationValue.startsWith(bearer)) {
// token
String token = authorizationValue.substring(bearer.length());
SysUser sysUser = tokenUtils.validationToken(token);
if(sysUser ! =null) {
// Spring Security role names start with "ROLE_" by default
Add can add multiple user roles. For a system with multiple user roles,
// Multiple user roles can be stored by adding user role tables and user-role mapping tables
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority("ROLE_" + sysUser.getUserRole()));
// Pass in the user name, password, and role. The password here is arbitrary. I don't need it
UserDetails userDetails = new User(sysUser.getUsername(), "password", authorities);
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
authentication.setDetails(userDetails.getUsername());
/ / authorizationSecurityContextHolder.getContext().setAuthentication(authentication); } } filterChain.doFilter(request, response); }}Copy the code
ErrorAuthenticationEntryPoint: error message class, unauthorized access through such return 401 unauthorized access to information. The custom of Spring Security AuthenticationEntryPoint unauthorized access by default processing interface:
@Component
public class ErrorAuthenticationEntryPoint implements AuthenticationEntryPoint.Serializable {
private static final long serialVersionUID = 5200068540912465653L;
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
// Set the Json format to return
response.setContentType("application/json; charset=UTF-8");
// Set the HTTP status code to 401
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
// PrintWriter output Response Returns information
PrintWriter writer = response.getWriter();
ObjectMapper mapper = new ObjectMapper();
MyResponse myResponse = new MyResponse("error"."Unauthorized access");
// Output the object in JSON format. This can be done by overriding the toString() of MyResponse directly through myResponse.toString()writer.write(mapper.writeValueAsString(myResponse)); }}Copy the code
UserDetailsServiceImpl: To customize the implementation of UserDetailsService, the user name, user password, and user role are passed to Spring Security by rewriting the loadUserByUsername method of the UserDetailsService interface.
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Resource
private SysUserMapper sysUserMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
SysUser sysUser = sysUserMapper.selectByUsername(username);
if (sysUser == null ) {
throw new UsernameNotFoundException(username);
}
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
// Spring Security role names start with "ROLE_" by default
Add can add multiple user roles. For a system with multiple user roles,
// Multiple user roles can be stored by adding user role tables and user-role mapping tables
authorities.add(new SimpleGrantedAuthority("ROLE_" + sysUser.getUserRole()));
// Pass the user name, user password, and user role to Spring Security.
return newUser(sysUser.getUsername(), sysUser.getPassword(), authorities); }}Copy the code
SpringSecurityConfig: SpringSecurity configuration that configures the password storage encryption algorithm, adds interceptors, turns off the Session manager, allows cross-domain access, and allows unauthorized access to logins and registered apis.
@SuppressWarnings("SpringJavaAutowiringInspection")
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
@Resource
private UserDetailsServiceImpl userDetailsService;
@Resource
private ErrorAuthenticationEntryPoint errorAuthenticationEntryPoint;
@Resource
private TokenFilter tokenFilter;
@Autowired
public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
// Use BCryptPasswordEncoder to verify the password
authenticationManagerBuilder.userDetailsService(this.userDetailsService).passwordEncoder(passwordEncoder());
}
@Bean
public PasswordEncoder passwordEncoder(a) {
/ / BCrypt password
return new BCryptPasswordEncoder();
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean(a) throws Exception {
return super.authenticationManagerBean();
}
@Override
public void configure(HttpSecurity httpSecurity) throws Exception {
// Configure CSRF to be turned off to allow cross-domain access
httpSecurity.csrf().disable();
// Specify a handler class for error unauthorized access
httpSecurity.exceptionHandling().authenticationEntryPoint(errorAuthenticationEntryPoint);
/ / close the Session
httpSecurity.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
// Allow unauthorized access to the registered API
httpSecurity.authorizeRequests()
.antMatchers("/api/user/login"."/api/user/register")
.permitAll().anyRequest().authenticated();
// Add interceptor
httpSecurity.addFilterBefore(tokenFilter, UsernamePasswordAuthenticationFilter.class);
// Disable cachinghttpSecurity.headers().cacheControl(); }}Copy the code
At this point, the security configuration of the Token is complete.
2.3) API interface and interface service layer
Create a service package and create an interface service layer SysUserService:
@Service
public class SysUserService {
@Resource
private AuthenticationManager authenticationManager;
@Resource
private TokenUtils tokenUtils;
@Resource
private SysUserMapper sysUserMapper;
/** User login *@paramSysUser Login information *@returnToken */ returned by the user after successful login
public MyResponse login(final SysUser sysUser) {
try {
// Verify that the username and password are correct
System.out.println(sysUser.getUsername());
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(sysUser.getUsername(),
sysUser.getPassword()));
} catch (BadCredentialsException e) {
return new MyResponse("ERROR"."Incorrect username or password");
}
// Generate tokens and query user permissions
SysUser sysUserData = sysUserMapper.selectByUsername(sysUser.getUsername());
return new MyResponse("SUCCESS",
tokenUtils.createToken(sysUserData));
}
/** User registration *@paramSysUser User registration information *@returnUser registration result */
public MyResponse save(SysUser sysUser) throws DataAccessException {
try {
// Password encrypted storage
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
String password = bCryptPasswordEncoder.encode(sysUser.getPassword());
sysUser.setPassword(password);
sysUserMapper.insert(sysUser);
} catch (DataAccessException e) {
return new MyResponse("ERROR"."The username or nickname already exists, or the user permissions are incorrect.");
}
return new MyResponse("SUCCESS"."User added successfully"); }}Copy the code
SysUserController: RESTful API interface. @preauthorize (“hasRole(‘ADMIN’)”) specifies that users with ADMIN permission can access the interface
@RestController
@RequestMapping(value = "/api/user")
public class SysUserController {
@Resource
private SysUserService sysUserService;
/** User login interface *@paramSysUser User name and password *@returnUser Token and role *@throwsAuthenticationException An authentication error throws an exception */
@PostMapping(value = "/login")
public MyResponse login(@RequestBody final SysUser sysUser) throws AuthenticationException {
return sysUserService.login(sysUser);
}
/** User registration interface *@paramSysUser User registration information *@returnUser registration result */
@PostMapping(value = "/register")
public MyResponse register(@RequestBody @Valid final SysUser sysUser) {
return sysUserService.save(sysUser);
}
/** This is only for logged-in users */
@PostMapping(value = "/message")
public String message(a) {
return "This message can only be seen by the logged in user.";
}
/** * This is only for administrators to see */
@PostMapping(value = "/admin")
@PreAuthorize("hasRole('ADMIN')")
public String admin(a) {
return "This message is viewable only by admin users."; }}Copy the code
2.4) run
Run the project to register, log in, and access the authorized user interface respectively.
Register: Register the ADMIN and USER users respectively
Login:
Authorization using tokens: / API /user/admin and/API /user/message
Appendix, Maven Project configuration
<dependencies>
<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>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.1</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.1</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId> <! -- or jjwt-gson if Gson is preferred -->
<version>0.11.1</version>
<scope>runtime</scope>
</dependency>
<! -- Uncomment this next dependency if you are using JDK 10 or earlier and you also want to use RSASSA-PSS (PS256, PS384, PS512) algorithms. JDK 11 or later does not require it for those algorithms: < the dependency > < groupId > org. Bouncycastle < / groupId > < artifactId > bcprov - jdk15on < / artifactId > < version > 1.60 < / version > <scope>runtime</scope> </dependency> -->
</dependencies>
Copy the code
This section mainly uses Spring Boot to integrate Spring Security and JJWT to realize the RESTful API interface of Token authentication and authorization, and to realize the functions of user registration, login, and role control. In the next section, the actual Spring Boot will integrate Apache Shiro, another commonly used security framework, to achieve Token authentication and authorization RESTful API interfaces. The following sequence of articles arranged
- Apache Shiro implements RESTful apis for Token authentication and authorization
- Apache Shiro realizes wechat code scanning login