OAuth2 Overview OAuth2 depends on the application scenario, These modes are classified into four types: Authorization Code Simplified Mode Resource owner password Credentials Client credentials In the project, we usually use the authorization code mode, which is the most complex mode among the four modes. Usually, microblog and QQ third-party login frequently appear in websites will adopt this mode. Oauth2 Authorization consists of the following two components: Authorization Server: authentication service Resource Server: Resource service In actual projects, the two services can be deployed on one server or separately. Here’s how to use it in conjunction with Spring Boot.
Build table
Client information can be stored in memory, redis, and databases. Redis and database storage are commonly used in real projects. This article uses a database. Spring 0Auth2 has designed the database tables and is immutable.
The script for creating the 0Auth2 database is as follows:
DROP TABLE IF EXISTS clientdetails
; DROP TABLE IF EXISTS oauth_access_token
; DROP TABLE IF EXISTS oauth_approvals
; DROP TABLE IF EXISTS oauth_client_details
; DROP TABLE IF EXISTS oauth_client_token
; DROP TABLE IF EXISTS oauth_refresh_token
;
CREATE TABLE clientdetails
( appId
varchar(128) NOT NULL, resourceIds
varchar(256) DEFAULT NULL, appSecret
varchar(256) DEFAULT NULL, scope
varchar(256) DEFAULT NULL, grantTypes
varchar(256) DEFAULT NULL, redirectUrl
varchar(256) DEFAULT NULL, authorities
varchar(256) DEFAULT NULL, access_token_validity
int(11) DEFAULT NULL, refresh_token_validity
int(11) DEFAULT NULL, additionalInformation
varchar(4096) DEFAULT NULL, autoApproveScopes
varchar(256) DEFAULT NULL, PRIMARY KEY (appId
) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE oauth_access_token
( token_id
varchar(256) DEFAULT NULL, token
blob, authentication_id
varchar(128) NOT NULL, user_name
varchar(256) DEFAULT NULL, client_id
varchar(256) DEFAULT NULL, authentication
blob, refresh_token
varchar(256) DEFAULT NULL, PRIMARY KEY (authentication_id
) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE oauth_approvals
( userId
varchar(256) DEFAULT NULL, clientId
varchar(256) DEFAULT NULL, scope
varchar(256) DEFAULT NULL, status
varchar(10) DEFAULT NULL, expiresAt
datetime DEFAULT NULL, lastModifiedAt
datetime DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE oauth_client_details
( client_id
varchar(128) NOT NULL, resource_ids
varchar(256) DEFAULT NULL, client_secret
varchar(256) DEFAULT NULL, scope
varchar(256) DEFAULT NULL, authorized_grant_types
varchar(256) DEFAULT NULL, web_server_redirect_uri
varchar(256) DEFAULT NULL, authorities
varchar(256) DEFAULT NULL, access_token_validity
int(11) DEFAULT NULL, refresh_token_validity
int(11) DEFAULT NULL, additional_information
varchar(4096) DEFAULT NULL, autoapprove
varchar(256) DEFAULT NULL, PRIMARY KEY (client_id
) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE oauth_client_token
( token_id
varchar(256) DEFAULT NULL, token
blob, authentication_id
varchar(128) NOT NULL, user_name
varchar(256) DEFAULT NULL, client_id
varchar(256) DEFAULT NULL, PRIMARY KEY (authentication_id
) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS oauth_code
; CREATE TABLE oauth_code
( code
varchar(256) DEFAULT NULL, authentication
blob ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE oauth_refresh_token ( token_id varchar(256) DEFAULT NULL, token blob, authentication blob ) ENGINE=InnoDB DEFAULT CHARSET=utf8; For testing purposes, let’s insert a piece of client information.
INSERT INTO oauth_client_details VALUES (‘dev’, ”, ‘dev’, ‘app’, ‘password,client_credentials,authorization_code,refresh_token’, ‘www.baidu.com’, ”, 3600, 3600, ‘{“country”:”CN”,”country_code”:”086″}’, ‘false’); The table for users, permissions, and roles is as follows:
DROP TABLE IF EXISTS user
; DROP TABLE IF EXISTS role
; DROP TABLE IF EXISTS user_role
; DROP TABLE IF EXISTS role_permission
; DROP TABLE IF EXISTS permission
;
CREATE TABLE user
( id
bigint(11) NOT NULL AUTO_INCREMENT, username
varchar(255) NOT NULL, password
varchar(255) NOT NULL, PRIMARY KEY (id
) ); CREATE TABLE role
( id
bigint(11) NOT NULL AUTO_INCREMENT, name
varchar(255) NOT NULL, PRIMARY KEY (id
) ); CREATE TABLE user_role
( user_id
bigint(11) NOT NULL, role_id
bigint(11) NOT NULL ); CREATE TABLE role_permission
( role_id
bigint(11) NOT NULL, permission_id
bigint(11) NOT NULL ); CREATE TABLE permission
( id
bigint(11) NOT NULL AUTO_INCREMENT, url
varchar(255) NOT NULL, name
varchar(255) NOT NULL, description
varchar(255) NULL, pid
bigint(11) NOT NULL, PRIMARY KEY (id
) );
INSERT INTO user (id, username, password) VALUES (1,’user’,’e10adc3949ba59abbe56e057f20f883e’); INSERT INTO user (id, username , password) VALUES (2,’admin’,’e10adc3949ba59abbe56e057f20f883e’); INSERT INTO role (id, name) VALUES (1,’USER’); INSERT INTO role (id, name) VALUES (2,’ADMIN’); INSERT INTO permission (id, url, name, pid) VALUES (1,’/’,”,0); INSERT INTO permission (id, url, name, pid) VALUES (2,’/’,”,0); INSERT INTO user_role (user_id, role_id) VALUES (1, 1); INSERT INTO user_role (user_id, role_id) VALUES (2, 2); INSERT INTO role_permission (role_id, permission_id) VALUES (1, 1); INSERT INTO role_permission (role_id, permission_id) VALUES (2, 2); The project structure
resources |____templates | |____login.html | |____application.yml java |____com | |____gf | | |____SpringbootSecurityApplication.java | | |____config | | | |____SecurityConfig.java | | | |____MyFilterSecurityInterceptor.java | | | |____MyInvocationSecurityMetadataSourceService.java | | | |____ResourceServerConfig.java | | | |____WebResponseExceptionTranslateConfig.java | | | |____AuthorizationServerConfiguration.java | | | |____MyAccessDecisionManager.java | | |____entity | | | |____User.java | | | |____RolePermisson.java | | | |____Role.java | | |____mapper | | | |____PermissionMapper.java | | | |____UserMapper.java | | | |____RoleMapper.java | | |____controller | | | |____HelloController.java | | | |____MainController.java | | |____service | | | |____MyUserDetailsService.java
XML org.springframework.boot spring-boot-starter-security org.springframework.boot spring-boot-starter-thymeleaf org.springframework.boot spring-boot-starter-oauth2-client org.springframework.boot spring-boot-starter-oauth2-resource-server org.springframework.security.oauth.boot spring-security-oauth2-autoconfigure 2.1.3.RELEASE SecurityConfig Supports password mode To configure AuthenticationManager
@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired private MyUserDetailsService userService; @ Override protected void the configure (AuthenticationManagerBuilder auth) throws the Exception {/ / check user auth. UserDetailsService ( UserService. PasswordEncoder(new passwordEncoder() {Override public String encode(CharSequence) charSequence) { System.out.println(charSequence.toString()); return DigestUtils.md5DigestAsHex(charSequence.toString().getBytes()); } @override public Boolean matches(CharSequence CharSequence, CharSequence) String s) { String encode = DigestUtils.md5DigestAsHex(charSequence.toString().getBytes()); boolean res = s.equals( encode ); return res; }}); } @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable(); http.requestMatchers() .antMatchers("/oauth/**","/login","/login-error") .and() .authorizeRequests() .antMatchers("/oauth/**").authenticated() .and() .formLogin().loginPage( "/login" ).failureUrl( "/login-error" ); } @Override @Bean public AuthenticationManager authenticationManagerBean() throws Exception{ return super.authenticationManager(); } @Bean public PasswordEncoder passwordEncoder() { return new PasswordEncoder() { @Override public String encode(CharSequence charSequence) { return charSequence.toString(); } @Override public boolean matches(CharSequence charSequence, String s) { return Objects.equals(charSequence.toString(),s); }}; }Copy the code
} AuthorizationServerConfiguration authentication server configuration
/ * *
-
Authentication server Configuration * / @ Configuration @ EnableAuthorizationServer public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
/ * *
- Grant type */ @autoWired Private AuthenticationManager AuthenticationManager;
/ * *
- */ @autoWired Private MyUserDetailsService userDetailsService;
/ * *
- */ @autowired private DataSource DataSource;
/ * *
- */ @autoWired Private TokenStore TokenStore;
@Autowired private WebResponseExceptionTranslator webResponseExceptionTranslator;
@Bean public TokenStore tokenStore() { return new JdbcTokenStore( dataSource ); }
@ Override public void the configure (AuthorizationServerSecurityConfigurer security) throws the Exception {/ * * * configuration oauth2 cross-domain/service CorsConfigurationSource source = new CorsConfigurationSource() { @Override public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { CorsConfiguration corsConfiguration = new CorsConfiguration(); corsConfiguration.addAllowedHeader(“”); corsConfiguration.addAllowedOrigin(request.getHeader( HttpHeaders.ORIGIN)); corsConfiguration.addAllowedMethod(“*”); corsConfiguration.setAllowCredentials(true); corsConfiguration.setMaxAge(3600L); return corsConfiguration; }};
security.tokenKeyAccess("permitAll()") .checkTokenAccess("permitAll()") .allowFormAuthenticationForClients() .addTokenEndpointAuthenticationFilter(new CorsFilter(source)); Copy the code
}
@Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.jdbc(dataSource); }
@ Override public void the configure (AuthorizationServerEndpointsConfigurer endpoints) throws the Exception {/ / password authentication type endpoints.authenticationManager(authenticationManager); // Configure the token storage mode endPoints. TokenStore (tokenStore); / / custom login or authentication failed to return information endpoints. The exceptionTranslator (webResponseExceptionTranslator); / / to use refresh_token, need additional configuration userDetailsService endpoints. The userDetailsService (userDetailsService);
}
} ResourceServerConfig Resource server configuration
/ * *
-
*/ @Configuration@enableresourceserver Public Class ResourceServerConfig extends ResourceServerConfigurerAdapter {
/ * *
- Set the URL that requires token authentication
- The url can screen out in WebSecurityConfigurerAdapter,
- For the same URL, if authentication is configured for both
- Enter the ResourceServerConfigurerAdapter, will be the priority for token authentication. It’s not going to
- WebSecurityConfigurerAdapter basic auth or forms authentication. */ @Override public void configure(HttpSecurity http) throws Exception { http.requestMatchers().antMatchers(“/hi”) .and() .authorizeRequests() .antMatchers(“/hi”).authenticated(); }
} key code is these, other class code refer to the source code address provided below.
Verify the password authorization mode. [Password mode requires parameters: username, password, grant_type, client_id, client_secret]
The request token
curl -X POST -d “username=admin&password=123456&grant_type=password&client_id=dev&client_secret=dev” Return to http://localhost:8080/oauth/token
{ “access_token”: “d94ec0aa-47ee-4578-b4a0-8cf47f0e8639”, “token_type”: “bearer”, “refresh_token”: “23503BC7-4494-4795-A047-98DB75053374 “,” expiRES_IN “: 3475, “scope”: “app”} Do not carry token to access resources,
curl http://localhost:8080/hi? Name =zhangsan An unauthorized message is displayed
{“error”: “unauthorized”, “error_description”: “Full authentication is required to access this resource”} Access resources with a token
curl http://localhost:8080/hi? Name = zhangsan&Access _token=164471f7-6fc6-4890-b5d2-eb43bda3328a The output is correct
Hi, Zhangsan refreshing token
curl -X POST -d ‘grant_type=refresh_token&refresh_token=23503bc7-4494-4795-a047-98db75053374&client_id=dev&client_secret=dev’ Return to http://localhost:8080/oauth/token
{ “access_token”: “ef53eb01-eb9b-46d8-bd58-7a0f9f44e30b”, “token_type”: “bearer”, “refresh_token”: “23503bc7-4494-4795-a047-98db75053374”, “expires_in”: 3599, “scope”: “App”} Client authorization mode [Client mode requires parameters: grant_type, client_id, client_secret]
The request token
The curl -x POST – d “grant_type = client_credentials & client_id = dev&client _secret = dev” http://localhost:8080/oauth/token to return
{ “access_token”: “a7be47b3-9dc8-473e-967a-c7267682dc66”, “token_type”: “bearer”, “expires_in”: 3564, “scope”: “App”} License code mode to obtain code
Access the following address in the browser:
Jump to the login page, http://localhost:8080/oauth/authorize?response_type=code&client_id=dev&redirect_uri=http://www.baidu.com Enter your account and password for authentication:
Change a token by code
curl -X POST -d “grant_type=authorization_code&code=qS03iu&client_id=dev&client_secret=dev&redirect_uri=http://www.baidu.com” http://localhost:8080/oauth/token
return
{ “access_token”: “90a246fa-a9ee-4117-8401-ca9c869c5be9”, “token_type”: “bearer”, “refresh_token”: “23503bc7-4494-4795-a047-98db75053374”, “expires_in”: 3319, “scope”: “app” }