当前位置:网站首页>Oauth2 server set up oauth2 authentication service
Oauth2 server set up oauth2 authentication service
2022-07-24 08:31:00 【Code road hero】
The source code of this tutorial
https://github.com/bestaone/HiAuth
The source code is relatively comprehensive , I will only introduce the key code in the tutorial
key word
- Microservice certification
- Oauth2
- authentication center
- springboot
- spring-cloud-starter-oauth2
- Integrate Oauth2
- Oauth2 client
Introduce
Here I will introduce two parts
- Oauth2 server Development of (aiwan-web-auth modular )
- Oauth2 client Development of (aiwan-web-mall modular )
design sketch

Redeposit failed Upload again Cancel 
Redeposit failed Upload again Cancel 
Oauth2 server build
- Database table (mysql5.6), Only one sys_user The watch is under our control , Other tables are controlled by the frame
CREATE TABLE `clientdetails` (
`appId` varchar(255) 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(255) 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` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`lastModifiedAt` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `oauth_client_details` (
`client_id` varchar(255) 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(2560) 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;
INSERT INTO `oauth_client_details` VALUES ('client', null, '$2a$10$1N/.LvTJuYpvxDzoJ1KdvuPDdV/kDSQE9Cxm9BzB1PreyzK6gmFRe', 'ALL,AUTH,USER,GOODS,ORDER', 'authorization_code,client_credentials,password,refresh_token', 'http://localhost:8081/mall/callback,http://localhost:9080/user/webjars/springfox-swagger-ui/oauth2-redirect.html,http://localhost:9081/goods/webjars/springfox-swagger-ui/oauth2-redirect.html,http://localhost:9082/order/webjars/springfox-swagger-ui/oauth2-redirect.html,http://localhost/user/webjars/springfox-swagger-ui/oauth2-redirect.html,http://localhost/goods/webjars/springfox-swagger-ui/oauth2-redirect.html,http://localhost/order/webjars/springfox-swagger-ui/oauth2-redirect.html', 'ROLE_USER', '1800', '86400', null, 'false');
CREATE TABLE `oauth_client_token` (
`token_id` varchar(256) DEFAULT NULL,
`token` blob,
`authentication_id` varchar(255) NOT NULL,
`user_name` varchar(256) DEFAULT NULL,
`client_id` varchar(256) DEFAULT NULL,
PRIMARY KEY (`authentication_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
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;
CREATE TABLE `sys_user` (
`id` bigint(20) NOT NULL,
`name` varchar(20) DEFAULT NULL,
`username` varchar(20) NOT NULL,
`password` varchar(128) NOT NULL,
`tel` varchar(20) DEFAULT NULL,
`gender` varchar(10) DEFAULT NULL,
`createTime` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `unique_username` (`username`),
UNIQUE KEY `unique_tel` (`tel`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `sys_user` VALUES ('1', ' Zhang San ', 'admin', '123456', '13712345678', 'MALE', '2018-12-03 17:57:12');
INSERT INTO `sys_user` VALUES ('2', ' Li Si ', 'user', '123456', '13812345678', 'UNKNOWN', '2018-12-03 17:57:12');
- pom.xml as follows
<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>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
<version>2.0.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>- add table sys_user Of service、mapper
@Mapper
public interface UserMapper {
@Insert("INSERT INTO sys_user(id,name,username,password,tel,gender,createTime) VALUES(#{id},#{name},#{username},#{password},#{tel},#{gender},#{createTime})")
void insert(User user);
@Delete("DELETE FROM sys_user WHERE id = #{id}")
void delete(Long id);
@Update("UPDATE sys_user SET name=#{name},username=#{username},password=#{password},tel=#{tel},gender=#{gender},createTime=#{createTime} WHERE id =#{id}")
int update(User user);
@ResultMap("BaseResultMap")
@Select("SELECT * FROM sys_user WHERE id=#{id}")
User findById(Long id);
@ResultMap("BaseResultMap")
@Select("SELECT * FROM sys_user WHERE username=#{username}")
User findByUsername(String username);
@ResultMap("BaseResultMap")
@Select("SELECT * FROM sys_user WHERE tel=#{tel}")
User findByTel(String tel);
@ResultMap("BaseResultMap")
@Select("SELECT * FROM sys_user")
List<User> findAll();
@ResultMap("BaseResultMap")
@Select("SELECT * FROM sys_user WHERE name like #{name}")
List<User> findByName(String name);
}
@Service
public class UserServiceImpl implements UserService {
@Resource
UserMapper mapper;
@Override
public User save(User user) {
if(user.getId()!=null){
mapper.update(user);
} else {
user.setId(System.currentTimeMillis());
mapper.insert(user);
}
return user;
}
@Override
public User findById(Long id) {
return mapper.findById(id);
}
@Override
public User findByUsername(String username) {
return mapper.findByUsername(username);
}
@Override
public User findByTel(String tel) {
return mapper.findByTel(tel);
}
@Override
public List<User> findAll() {
return mapper.findAll();
}
@Override
public void delete(Long id) {
mapper.delete(id);
}
@Override
public List<User> findByName(String name) {
return mapper.findByName("%" + name + "%");
}
}
- Add login interception
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Bean
public UserDetailsService simpleUserDetailsService(){
return new UserDetailsServiceImpl();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(simpleUserDetailsService());
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.userDetailsService(userDetailsService());
http.csrf().disable();
http.formLogin()
.loginPage("/signin").loginProcessingUrl("/signin/form/account").defaultSuccessUrl("/index")
.and()
.logout().logoutUrl("/signout").logoutSuccessUrl("/signin")
.and()
.authorizeRequests()
.antMatchers("/signin","/signin/form/tel","/code/image","/code/mobile","/static/**").permitAll()
.antMatchers("/oauth/**").permitAll()
.antMatchers("/user/**").hasAnyRole("USER","ADMIN")
.anyRequest().authenticated();
}
}
- Add login form signin.html
<div class="tab-pane fade in active" id="account-login">
<form th:action="@{/signin/form/account}" method="post">
<label for="username" class="sr-only"> user name </label>
<input class="form-control" type="text" name="username" id="username" value="user" placeholder=" account number " required>
<label for="password" class="sr-only"> password </label>
<input class="form-control" type="password" name="password" id="password" value="123456" placeholder=" password " required>
<button class="btn btn-lg btn-primary btn-block" type="submit"> Sign in </button>
</form>
</div>
- Oauth2 server Config
@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private Environment env;
@Autowired
private AuthenticationManager authenticationManager;
/**
* Custom authorization page
*/
@Autowired
private AuthorizationEndpoint authorizationEndpoint;
@PostConstruct
public void init() {
authorizationEndpoint.setUserApprovalPage("forward:/oauth/my_approval_page");
authorizationEndpoint.setErrorPage("forward:/oauth/my_error_page");
}
@Bean
public DataSource dataSource() {
final DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty("spring.datasource.driver-class-name"));
dataSource.setUrl(env.getProperty("spring.datasource.url"));
dataSource.setUsername(env.getProperty("spring.datasource.username"));
dataSource.setPassword(env.getProperty("spring.datasource.password"));
return dataSource;
}
@Bean
public ApprovalStore approvalStore() {
return new JdbcApprovalStore(dataSource());
}
@Bean
protected AuthorizationCodeServices authorizationCodeServices() {
return new JdbcAuthorizationCodeServices(dataSource());
}
@Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource());
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// oauth_client_details
clients.jdbc(dataSource());
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
// oauth_approvals
endpoints.approvalStore(approvalStore());
// oauth_code
endpoints.authorizationCodeServices(authorizationCodeServices());
// oauth_access_token & oauth_refresh_token
endpoints.tokenStore(tokenStore());
// Support password grant type
endpoints.authenticationManager(authenticationManager);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
oauthServer.allowFormAuthenticationForClients();
}
}
Oauth2 client build
- pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>com.github.scribejava</groupId>
<artifactId>scribejava-apis</artifactId>
<version>5.0.0</version>
</dependency>
- DefaultApi20
public class AiwanApi extends DefaultApi20 {
private String accessTokenEndpoint = "http://localhost:8080/oauth/token";
private String authorizationBaseUrl = "http://localhost:8080/oauth/authorize";
protected AiwanApi() {}
private static class InstanceHolder {
private static final AiwanApi INSTANCE = new AiwanApi();
}
public static AiwanApi instance() {
return InstanceHolder.INSTANCE;
}
@Override
public String getAccessTokenEndpoint() {
return accessTokenEndpoint;
}
@Override
protected String getAuthorizationBaseUrl() {
return authorizationBaseUrl;
}
@Override
public TokenExtractor<OAuth2AccessToken> getAccessTokenExtractor() {
return OAuth2AccessTokenJsonExtractor.instance();
}
@Override
public OAuth20Service createService(OAuthConfig config) {
return new AiwanService(this, config);
}
}
- OAuth20Service
public class AiwanService extends OAuth20Service {
public AiwanService(DefaultApi20 api, OAuthConfig config) {
super(api, config);
}
@Override
protected OAuthRequest createAccessTokenRequest(String code) {
final OAuthRequest request = new OAuthRequest(getApi().getAccessTokenVerb(), getApi().getAccessTokenEndpoint());
final OAuthConfig config = getConfig();
request.addParameter(OAuthConstants.CLIENT_ID, config.getApiKey());
final String apiSecret = config.getApiSecret();
if (apiSecret != null) {
request.addParameter(OAuthConstants.CLIENT_SECRET, apiSecret);
}
request.addParameter(OAuthConstants.CODE, code);
request.addParameter(OAuthConstants.REDIRECT_URI, config.getCallback());
final String scope = config.getScope();
if (scope != null) {
request.addParameter(OAuthConstants.SCOPE, scope);
}
request.addParameter(OAuthConstants.GRANT_TYPE, OAuthConstants.AUTHORIZATION_CODE);
request.addHeader(OAuthConstants.HEADER,
OAuthConstants.BASIC + ' '
+ Base64Encoder.getInstance()
.encode(String.format("%s:%s", config.getApiKey(), apiSecret).getBytes(Charset.forName("UTF-8"))));
return request;
}
}
- obtain access_token
@Controller
public class IndexController {
private static Logger logger = LoggerFactory.getLogger(IndexController.class);
private static final String SESSION_KEY_ACCESS_TOKEN = "MY_ACCESS_TOKEN";
/**
* To prevent CSRF Cross Station attack , Each request STATE The value of should be different , You can put Session!
* Because it's all localhost test , therefore session Can't keep , Use a fixed value .
*/
private static final String STATE = "secret-rensanning";
private static final String CLIENT_ID = "client";
private static final String CLIENT_SECRET = "123456";
private static final String CALLBACK_URL = "http://localhost:8081/mall/callback";
private static final String SCOPE = "ALL";
private OAuth20Service aiwanApi = new ServiceBuilder(CLIENT_ID)
.apiSecret(CLIENT_SECRET)
.scope(SCOPE)
.state(STATE)
.callback(CALLBACK_URL)
.build(AiwanApi.instance());
@GetMapping("/")
public String index() {
return "index";
}
@GetMapping("/signin")
public void signin(HttpServletRequest request, HttpServletResponse response) throws IOException {
logger.debug("signin");
logger.info("session id:{}", request.getSession().getId());
String authorizationUrl = aiwanApi.getAuthorizationUrl();
logger.info("redirectURL:{}", authorizationUrl);
response.sendRedirect(authorizationUrl);
}
@GetMapping("/callback")
public String callback(@RequestParam(value = "code", required = false) String code,
@RequestParam(value = "state", required = false) String state, HttpServletRequest request) throws Exception {
logger.debug("callback [code:{}],[state:{}],[sessionId:{}]", code, state, request.getSession().getId());
if (STATE.equals(state)) {
logger.info("State OK!");
} else {
logger.error("State NG!");
}
OAuth2AccessToken accessToken = aiwanApi.getAccessToken(code);
request.getSession().setAttribute(SESSION_KEY_ACCESS_TOKEN, accessToken);
return "profile";
}
}
Please move the source code of this tutorial [https://github.com/bestaone/Aiwan]
边栏推荐
- JMX console unauthorized access vulnerability
- Use the bark app to realize the process of pushing messages to mobile phones
- 栈/堆/队列刷题(下)
- "Problem solving" Batman's trouble
- MySQL index filesort
- Move protocol global health declaration, step into Web3 in sports
- Draw a circular radar chart with canvas
- [MySQL] installation tutorial and master-slave configuration
- G1 (garbage first) collector
- Shared lock, exclusive lock, mutex lock, pessimistic lock, optimistic lock, row lock, table lock, page lock, non repeatable read, lost modification, read dirty data
猜你喜欢

Four data interaction modes of go grpc

Wechat applet subscription message development process

Larave uses sanctum for API authentication

Figure New Earth: how the RVT format BIM model modeled by Revit can accurately match the map with texture

Move protocol starts with running and builds a healthy ecosystem of sports

Wechat payment V3 version of openresty implementation and pit avoidance Guide (service side)
![[MySQL] installation tutorial and master-slave configuration](/img/79/0ad3f68b69a0a03a62422d4cc70035.png)
[MySQL] installation tutorial and master-slave configuration

Digital collections "chaos", 100 billion market changes are coming?

Move protocol global health declaration, step into Web3 in sports

2022.7.11 overall solution
随机推荐
Local warehouse associated with remote warehouse
[multithreading] five communication modes between multithreads
「题解」零钱兑换
Why does the metauniverse need NFT?
[tools] a few lines of code can realize complex excel import and export tool classes, which is really strong!!!
Larave uses sanctum for API authentication
In 2022, how to choose cross end technology solutions?
How to write your FAQ page?
dba
"Problem solution" with score
Error lnk2019: unresolved external symbol [email protected]
Aquanee: the true meaning of "p2e"
Wei Xiaoli's "pursuer" is coming
Play to earn: a new and more promising game paradigm in the future
[wechat applet development (II)] custom navigation bar
Is it safe to open an account online in Beijing
WordPress free theme: document, making reading more convenient
【MySQL】08:聚合函数
JS string interception
图新地球:如何导入修改了高程基准(椭球)的CAD文件