1. Basic concepts
At present, the third version of auth.0, which is the most widely used authentication standard for users, provides a safe and easy-to-use version of auth. Auth for any user
Analyze the process of using vx authentication for websites:
1. First of all, if users want to access resources, they need to be authenticated and use third-party authentication, such as vx,qq, Sina, etc
2. If the user confirms to use the third-party authentication, he needs to request the authorization code from the corresponding third party. After obtaining the authorization code, he can use the obtained authorization code to authorize the server to request a token
3. The server verifies the token. If successful, it will grant the corresponding permission to access the resource and obtain the corresponding resource or personal information
Oauth2 this is for the convenience of safe users (third parties) to log in.
It must have been silly to hear oauth2 this word at first. What is this for authentication? For certification? For authorization? Is it the same thing as shiro(java)?
In fact, oauth is a process. We write code according to the requirements of this process
oauth has an authorization server. It is used as user authentication. For the server, only one oauth authorization server needs to be implemented. For users (calling the R & D of authorization and authentication), they only need to send a request according to the process.
Oauth has four entities. Let's use QQ to log in to microblog as an example.
Resource owner (ordinary user)
Resource server is the background server of QQ (get account, nickname, avatar, etc.).
Client microblogging is the platform
The authorization server authenticates QQ & for authorization.
oauth has four ways. The purpose is not to expose the password to third parties. (i.e. do not expose QQ account and password to microblog)
1. authorization code is also the version with the highest security level. It supports refresh token, which is generally used for microblog QQ login.
2. password credentials supports refresh token, which has a low security level. Who knows if the client will steal your password. General internal use
3. The simplified mode implicit does not support refresh token, which does not get the code. The request gives the token, but the advantage of not getting it
4. client credentials in client mode does not support refresh token, which is used by trusted internal clients. Generally used between internal platforms
Note: client_id client_secret is used by oauth server to authenticate clients.
Each method is described in detail below. Let's not talk about the simplified model.
1. Authorization code mode
Authorization code mode is to obtain double verification of verification code and token in the authorization server, and then authorize access
1) Add dependency:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.6.3</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>spring-sercrity-student</groupId> <artifactId>spring-sercrity-myself</artifactId> <version>1.0</version> <properties> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> <spring-cloud.version>2021.0.1</spring-cloud.version> </properties> <dependencyManagement> <dependencies> <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-oauth2 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-oauth2</artifactId> <version>2.2.5.RELEASE</version> </dependency> <!--When oauth2 An unreadable exception occurred during project startup. Add this dependency--> <dependency> <groupId>javax.xml.bind</groupId> <artifactId>jaxb-api</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-core</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-impl</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>javax.activation</groupId> <artifactId>activation</artifactId> <version>1.1.1</version> </dependency> <!--spring cloud integration security frame--> <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-security --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-security</artifactId> <version>2.2.4.RELEASE</version> </dependency> <!-- web modular --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> </project>
Add spring cloud dependency, and spring cloud also integrates security and oauth2 framework
2) Create securityconfig:
/** * Authorization framework configuration class */ @Configuration //Indicates that webSecurity is started @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests() //Release oauth authentication, login authentication, user exit .antMatchers("/oauth/**", "/login/**", "logout/**").permitAll() //Intercept all requests that have not been released .anyRequest().authenticated() .and() //Release all forms after certification .formLogin().permitAll(); } //Returns an encryptor @Bean public PasswordEncoder getPw() { return new BCryptPasswordEncoder(); } }
3) Custom user information wrapper class
/** * User information packaging */ public class User implements UserDetails { //user name private String userName; //User password private String password; //User rights private List<GrantedAuthority> authorities; public User(String userName, String password, List<GrantedAuthority> authorities) { this.userName = userName; this.password = password; this.authorities = authorities; } @Override public Collection<? extends GrantedAuthority> getAuthorities() { return authorities; } @Override public String getPassword() { return password; } @Override public String getUsername() { return userName; } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return true; } }
4) Custom authentication class
/** * Custom authentication */ @Service public class UserService implements UserDetailsService { @Autowired private PasswordEncoder passwordEncoder; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { String encodePw = passwordEncoder.encode("123"); return new User(username,encodePw, AuthorityUtils.commaSeparatedStringToAuthorityList("admin")); } }
This is just a demonstration. The actual password should be queried from the database for verification
5) Configure authorization server
/** * Authorization server configuration * * @author Qin Yang * @version 1.0 */ @Configuration //Indicates that authorization server configuration is enabled @EnableAuthorizationServer public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { @Autowired private PasswordEncoder passwordEncoder; @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() //It's only temporarily dead here. Normally, you need to authorize the server to register //Configure Client id .withClient("admin") //Configure client security .secret(passwordEncoder.encode("Vermouth2022")) //Set Token expiration time .accessTokenValiditySeconds(3600) //Redirect address, which is used to jump after successful authorization .redirectUris("http://www.baidu.com") //Scope of authorization, which part of the content to read .scopes("all") //Authorization type .authorizedGrantTypes("authorization_code"); } }
The client id and key obtained here will be verified at the same time during the second token verification!!!
6) Configure resource server
/** * Resource service configuration */ @Configuration @EnableResourceServer public class ResourceServerConfig extends ResourceServerConfigurerAdapter { @Override public void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .anyRequest().authenticated() .and() .requestMatchers() //Release the corresponding resources to be obtained .antMatchers("/user/**"); } }
When the token is verified successfully, the required functions are released
Specific operation process:
This is just a simulated login with authorization code. In fact, we usually go to vx this third party to obtain permission, so we also access their authorization server and resource manager, and this is to understand the process
When a user needs third-party authorization, we will use oauth protocol, and let the user scan or log in or face recognition to authenticate the user's identity, and send these authentication information to the authorization server
Authorization request: http://localhost:8080/oauth/authorize?response_type=code&client_id=admin&redirect_uri=http://www.baidu.com&scope=all
The url information here must be consistent with that defined in the authorization server, otherwise an error will be reported
/oauth / is the interface of our authorization framework
/Authorize means to authorize and request a verification code. The client id is admin. After success, jump to Baidu. The requested permission range is all
When we visit, it will automatically jump to the login interface and let us authenticate
After entering the account password / scanning the code, you will successfully enter our authorized page
Approve means to agree to the authorization and Dent means to refuse
After agreeing, we jump to the designated page
Look carefully, the url of the page contains a code, and its value is a verification code returned by our authorization server
When we get the verification code, we need to go to the authorization server for verification
To send messages with post requests, we use postman
Use the verification code for authentication, and input the client id we wrote in the authorization server. This should be registered under normal circumstances. It is written to death for demonstration
At the same time, the parameters required by the authorization server and the returned verification code should be carried in the request body
After clicking send, we get a token and some information returned by the authorization server
{ "access_token": "5afbda45-62aa-4345-bd20-a4e647356cf2", "token_type": "bearer", "expires_in": 3599, "scope": "all" }
After you get the token, you can access the resources we need. Take this token to make a request
After submitting, we will access the functions we need, and then get the corresponding resources. This is the authorization code mode