Springboot Oauth2 Server搭建Oauth2认证服务的示例
导读:本文共10360.5字符,通常情况下阅读需要35分钟。同时您也可以点击右侧朗读,来听本文内容。按键盘←(左) →(右) 方向键可以翻页。
摘要:介绍这里我将介绍两个部分Oauth3 server 的开发 (hi-auth-web模块)Oauth3 client 的开发 (hi-mall-web模块)效果图himall.gifumc.gifLIVE DEMOHiMall: http://hiauth.cn/himallUMC: http://hiauth.cn/umcSwagger2:http://hiauth.cn/hiauth/swag... ...
目录
(为您整理了一些要点),点击可以直达。介绍
这里我将介绍两个部分
Oauth3 server 的开发 (hi-auth-web模块)
Oauth3 client 的开发 (hi-mall-web模块)
效果图
himall.gif
umc.gif
LIVE DEMO
HiMall: http://hiauth.cn/himall
UMC: http://hiauth.cn/umc
Swagger2:http://hiauth.cn/hiauth/swagger-ui.html
Oauth3 server 搭建
数据库表(mysql5.6),其中只有sys_user表由我们自己控制,其他表由框架控制
CREATETABLEclientdetails
(appId
varchar(255)NOTNULL,resourceIds
varchar(256)DEFAULTNULL,appSecret
varchar(256)DEFAULTNULL,scope
varchar(256)DEFAULTNULL,grantTypes
varchar(256)DEFAULTNULL,redirectUrl
varchar(256)DEFAULTNULL,authorities
varchar(256)DEFAULTNULL,access_token_validity
int(11)DEFAULTNULL,refresh_token_validity
int(11)DEFAULTNULL,additionalInformation
varchar(4096)DEFAULTNULL,autoApproveScopes
varchar(256)DEFAULTNULL,
PRIMARYKEY(appId
)
)ENGINE=InnoDBDEFAULTCHARSET=utf8;CREATETABLE
oauth_access_token
(token_id
varchar(256)DEFAULTNULL,token
blob,authentication_id
varchar(255)NOTNULL,user_name
varchar(256)DEFAULTNULL,client_id
varchar(256)DEFAULTNULL,authentication
blob,refresh_token
varchar(256)DEFAULTNULL,
PRIMARYKEY(authentication_id
)
)ENGINE=InnoDBDEFAULTCHARSET=utf8;CREATETABLE
oauth_approvals
(userId
varchar(256)DEFAULTNULL,clientId
varchar(256)DEFAULTNULL,scope
varchar(256)DEFAULTNULL,status
varchar(10)DEFAULTNULL,expiresAt
timestampNOTNULLDEFAULTCURRENT_TIMESTAMPONUPDATECURRENT_TIMESTAMP,lastModifiedAt
timestampNOTNULLDEFAULT'0000-00-0000:00:00'
)ENGINE=InnoDBDEFAULTCHARSET=utf8;CREATETABLE
oauth_client_details
(client_id
varchar(255)NOTNULL,resource_ids
varchar(256)DEFAULTNULL,client_secret
varchar(256)DEFAULTNULL,scope
varchar(256)DEFAULTNULL,authorized_grant_types
varchar(256)DEFAULTNULL,web_server_redirect_uri
varchar(2560)DEFAULTNULL,authorities
varchar(256)DEFAULTNULL,access_token_validity
int(11)DEFAULTNULL,refresh_token_validity
int(11)DEFAULTNULL,additional_information
varchar(4096)DEFAULTNULL,autoapprove
varchar(256)DEFAULTNULL,
PRIMARYKEY(client_id
)
)ENGINE=InnoDBDEFAULTCHARSET=utf8;INSERTINTO
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/oauth3-redirect.html,http://localhost:9081/goods/webjars/springfox-swagger-ui/oauth3-redirect.html,http://localhost:9082/order/webjars/springfox-swagger-ui/oauth3-redirect.html,http://localhost/user/webjars/springfox-swagger-ui/oauth3-redirect.html,http://localhost/goods/webjars/springfox-swagger-ui/oauth3-redirect.html,http://localhost/order/webjars/springfox-swagger-ui/oauth3-redirect.html','ROLE_USER','1800','86400',null,'false');CREATETABLE
oauth_client_token
(token_id
varchar(256)DEFAULTNULL,token
blob,authentication_id
varchar(255)NOTNULL,user_name
varchar(256)DEFAULTNULL,client_id
varchar(256)DEFAULTNULL,
PRIMARYKEY(authentication_id
)
)ENGINE=InnoDBDEFAULTCHARSET=utf8;CREATETABLE
oauth_code
(code
varchar(256)DEFAULTNULL,authentication
blob
)ENGINE=InnoDBDEFAULTCHARSET=utf8;CREATETABLE
oauth_refresh_token
(token_id
varchar(256)DEFAULTNULL,token
blob,authentication
blob
)ENGINE=InnoDBDEFAULTCHARSET=utf8;CREATETABLE
sys_user
(id
bigint(20)NOTNULL,name
varchar(20)DEFAULTNULL,username
varchar(20)NOTNULL,password
varchar(128)NOTNULL,tel
varchar(20)DEFAULTNULL,gender
varchar(10)DEFAULTNULL,createTime
datetimeDEFAULTNULL,
PRIMARYKEY(id
),
UNIQUEKEYunique_username
(username
),
UNIQUEKEYunique_tel
(tel
)
)ENGINE=InnoDBDEFAULTCHARSET=utf8;INSERTINTO
sys_user
VALUES('1','张三','admin','123456','13712345678','MALE','2018-12-0317:57:12');
INSERTINTOsys_user
VALUES('2','李四','user','123456','13812345678','UNKNOWN','2018-12-0317:57:12');
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-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth3</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>
添加表sys_user的service、mapper
@Mapper
publicinterfaceUserMapper{@Insert("INSERTINTOsys_user(id,name,username,password,tel,gender,createTime)VALUES(#{id},#{name},#{username},#{password},#{tel},#{gender},#{createTime})")
voidinsert(Useruser);@Delete("DELETEFROMsys_userWHEREid=#{id}")
voiddelete(Longid);@Update("UPDATEsys_userSETname=#{name},username=#{username},password=#{password},tel=#{tel},gender=#{gender},createTime=#{createTime}WHEREid=#{id}")
intupdate(Useruser);@ResultMap("BaseResultMap")
@Select("SELECT*FROMsys_userWHEREid=#{id}")
UserfindById(Longid);@ResultMap("BaseResultMap")
@Select("SELECT*FROMsys_userWHEREusername=#{username}")
UserfindByUsername(Stringusername);@ResultMap("BaseResultMap")
@Select("SELECT*FROMsys_userWHEREtel=#{tel}")
UserfindByTel(Stringtel);@ResultMap("BaseResultMap")
@Select("SELECT*FROMsys_user")
List<User>findAll();@ResultMap("BaseResultMap")
@Select("SELECT*FROMsys_userWHEREnamelike#{name}")
List<User>findByName(Stringname);}
@Service
publicclassUserServiceImplimplementsUserService{@Resource
UserMappermapper;@Override
publicUsersave(Useruser){
if(user.getId()!=null){
mapper.update(user);
}else{
user.setId(System.currentTimeMillis());
mapper.insert(user);
}
returnuser;
}@Override
publicUserfindById(Longid){
returnmapper.findById(id);
}@Override
publicUserfindByUsername(Stringusername){
returnmapper.findByUsername(username);
}@Override
publicUserfindByTel(Stringtel){
returnmapper.findByTel(tel);
}@Override
publicList<User>findAll(){
returnmapper.findAll();
}@Override
publicvoiddelete(Longid){
mapper.delete(id);
}@Override
publicList<User>findByName(Stringname){
returnmapper.findByName("%"+name+"%");
}}
添加登录拦截
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
publicclassSecurityConfigextendsWebSecurityConfigurerAdapter{@Bean
publicPasswordEncoderpasswordEncoder(){
returnnewBCryptPasswordEncoder();
}@Bean
publicUserDetailsServicesimpleUserDetailsService(){
returnnewUserDetailsServiceImpl();
}@Override
protectedvoidconfigure(AuthenticationManagerBuilderauth)throwsException{
auth.userDetailsService(simpleUserDetailsService());
}@Override
@Bean
publicAuthenticationManagerauthenticationManagerBean()throwsException{
returnsuper.authenticationManagerBean();
}@Override
protectedvoidconfigure(HttpSecurityhttp)throwsException{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();}
}
添加登录表单signin.html
<divclass="tab-panefadeinactive"id="account-login">
<formth:action="@{/signin/form/account}"method="post">
<labelfor="username"class="sr-only">用户名</label>
<inputclass="form-control"type="text"name="username"id="username"value="user"placeholder="账号"required>
<labelfor="password"class="sr-only">密码</label>
<inputclass="form-control"type="password"name="password"id="password"value="123456"placeholder="密码"required>
<buttonclass="btnbtn-lgbtn-primarybtn-block"type="submit">登录</button>
</form>
</div>
Oauth3 server Config
@Configuration
@EnableAuthorizationServer
publicclassOAuth3AuthorizationConfigextendsAuthorizationServerConfigurerAdapter{@Autowired
privateEnvironmentenv;@Autowired
privateAuthenticationManagerauthenticationManager;/*
自定义授权页面
*/
@Autowired
privateAuthorizationEndpointauthorizationEndpoint;@PostConstruct
publicvoidinit(){
authorizationEndpoint.setUserApprovalPage("forward:/oauth/my_approval_page");
authorizationEndpoint.setErrorPage("forward:/oauth/my_error_page");
}@Bean
publicDataSourcedataSource(){
finalDriverManagerDataSourcedataSource=newDriverManagerDataSource();
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"));
returndataSource;
}@Bean
publicApprovalStoreapprovalStore(){
returnnewJdbcApprovalStore(dataSource());
}@Bean
protectedAuthorizationCodeServicesauthorizationCodeServices(){
returnnewJdbcAuthorizationCodeServices(dataSource());
}@Bean
publicTokenStoretokenStore(){
returnnewJdbcTokenStore(dataSource());
}@Override
publicvoidconfigure(ClientDetailsServiceConfigurerclients)throwsException{
//oauth_client_details
clients.jdbc(dataSource());
}@Override
publicvoidconfigure(AuthorizationServerEndpointsConfigurerendpoints){
//oauth_approvals
endpoints.approvalStore(approvalStore());
//oauth_code
endpoints.authorizationCodeServices(authorizationCodeServices());
//oauth_access_token&oauth_refresh_token
endpoints.tokenStore(tokenStore());
//支持passwordgranttype
endpoints.authenticationManager(authenticationManager);
}@Override
publicvoidconfigure(AuthorizationServerSecurityConfigureroauthServer){
oauthServer.allowFormAuthenticationForClients();
}
}
Oauth3 client 搭建
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
publicclassAiwanApiextendsDefaultApi20{privateStringaccessTokenEndpoint="http://localhost:8080/oauth/token";
privateStringauthorizationBaseUrl="http://localhost:8080/oauth/authorize";protectedAiwanApi(){}
privatestaticclassInstanceHolder{
privatestaticfinalAiwanApiINSTANCE=newAiwanApi();
}publicstaticAiwanApiinstance(){
returnInstanceHolder.INSTANCE;
}@Override
publicStringgetAccessTokenEndpoint(){
returnaccessTokenEndpoint;
}@Override
protectedStringgetAuthorizationBaseUrl(){
returnauthorizationBaseUrl;
}@Override
publicTokenExtractor<OAuth3AccessToken>getAccessTokenExtractor(){
returnOAuth3AccessTokenJsonExtractor.instance();
}@Override
publicOAuth30ServicecreateService(OAuthConfigconfig){
returnnewAiwanService(this,config);
}}
OAuth30Service
publicclassAiwanServiceextendsOAuth30Service{publicAiwanService(DefaultApi20api,OAuthConfigconfig){
super(api,config);
}@Override
protectedOAuthRequestcreateAccessTokenRequest(Stringcode){
finalOAuthRequestrequest=newOAuthRequest(getApi().getAccessTokenVerb(),getApi().getAccessTokenEndpoint());
finalOAuthConfigconfig=getConfig();
request.addParameter(OAuthConstants.CLIENT_ID,config.getApiKey());
finalStringapiSecret=config.getApiSecret();
if(apiSecret!=null){
request.addParameter(OAuthConstants.CLIENT_SECRET,apiSecret);
}
request.addParameter(OAuthConstants.CODE,code);
request.addParameter(OAuthConstants.REDIRECT_URI,config.getCallback());
finalStringscope=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"))));
returnrequest;
}
}
获取access_token
@Controller相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!
publicclassIndexController{privatestaticLoggerlogger=LoggerFactory.getLogger(IndexController.class);
privatestaticfinalStringSESSION_KEY_ACCESS_TOKEN="MY_ACCESS_TOKEN";
/*
为防止CSRF跨站攻击,每次请求STATE的值应该不同,可以放入Session!
由于都是localhost测试,所以session无法保持,用一个固定值。
/
privatestaticfinalStringSTATE="secret-rensanning";
privatestaticfinalStringCLIENT_ID="client";
privatestaticfinalStringCLIENT_SECRET="123456";
privatestaticfinalStringCALLBACK_URL="http://localhost:8081/mall/callback";
privatestaticfinalStringSCOPE="ALL";
privateOAuth30ServiceaiwanApi=newServiceBuilder(CLIENT_ID)
.apiSecret(CLIENT_SECRET)
.scope(SCOPE)
.state(STATE)
.callback(CALLBACK_URL)
.build(AiwanApi.instance());@GetMapping("/")
publicStringindex(){
return"index";
}@GetMapping("/signin")
publicvoidsignin(HttpServletRequestrequest,HttpServletResponseresponse)throwsIOException{
logger.debug("signin");
logger.info("sessionid:{}",request.getSession().getId());
StringauthorizationUrl=aiwanApi.getAuthorizationUrl();
logger.info("redirectURL:{}",authorizationUrl);
response.sendRedirect(authorizationUrl);
}@GetMapping("/callback")
publicStringcallback(@RequestParam(value="code",required=false)Stringcode,
@RequestParam(value="state",required=false)Stringstate,HttpServletRequestrequest)throwsException{logger.debug("callback[code:{}],[state:{}],[sessionId:{}]",code,state,request.getSession().getId());
if(STATE.equals(state)){
logger.info("StateOK!");
}else{
logger.error("StateNG!");
}OAuth3AccessTokenaccessToken=aiwanApi.getAccessToken(code);
request.getSession().setAttribute(SESSION_KEY_ACCESS_TOKEN,accessToken);return"profile";
}}
Springboot Oauth2 Server搭建Oauth2认证服务的示例的详细内容,希望对您有所帮助,信息来源于网络。