网站别人备案怎么办,东莞黄页顺企网,网站开发 弹窗,wordpress没有链接在前面的帖子中介绍了SpringSecurityJWT实现了认证和授权的功能。因为基于Oauth2的统一认证在项目需求中越来越多#xff0c;所以有必要将OAuth2的解决方案也整合进来#xff0c;这样我们的产品既可以作为一个业务系统#xff0c;也可以作为一个独立的统一认证服务器。下面详… 在前面的帖子中介绍了SpringSecurityJWT实现了认证和授权的功能。因为基于Oauth2的统一认证在项目需求中越来越多所以有必要将OAuth2的解决方案也整合进来这样我们的产品既可以作为一个业务系统也可以作为一个独立的统一认证服务器。下面详细介绍如何基于SpringSecurity实现OAuth2服务以及应用如何作为一个客户端调用OAuth2。
一、引入OAuth2依赖 因为SpringSecurity框架已经整合到项目里了现在我们只需要整合OAuth2的依赖。在openjweb-sys的模块中增加下面的依赖 dependencygroupIdorg.springframework.security.oauth.boot/groupIdartifactIdspring-security-oauth2-autoconfigure/artifactIdversion2.1.3.RELEASE/version/dependency另外需要在openjweb-sys的OpenjwebSysApplication.java类中增加注解EnableAuthorizationServer。 如果应用作为OAuth2 ServerSpring Security的WebSecurityConfig和之前介绍的会有所差异为了能够在OAuth2 Server和非OAuth2 Server之间切换也就是说根据项目需求来确定是否部署为OAuth2 Server我们在application-dev.yml中加一个配置参数
#is this server is oauth2 server
oauth2:server: true 当设置为true时作为 OAuth2 Server在本节中我们设置为true后面会介绍这个参数的使用。
二、本节需要实现的OAuth2功能 1、实现OAuth2 Server端和OAuth2 Client端 2、OAuth2授权码、根据授权码请求accessToken。 3、根据accessToken获取用户详情。 4、获取refreshToken。 5、客户端的Spring Security登录。
三、开发客户端管理功能 因为OAuth2框架需要通过clientId来识别不同的客户所以作为OAuth2服务需要实现一个客户端管理的功能我们可以基于Mybatis-plus实现为了简单起见暂实现查询功能即可测试数据从数据库中录入。 现在我们开发一个OAuth2客户端管理表名为comm_sso_client_app
CREATE TABLE comm_sso_client_app (row_id varchar(40) NOT NULL COMMENT 唯一行号,obj_name varchar(40) DEFAULT NULL COMMENT 名称,master_row_id varchar(40) DEFAULT NULL COMMENT 主表RowId,flow_trans_id varchar(40) DEFAULT NULL COMMENT 流程事务ID,sort_no bigint(20) DEFAULT NULL,create_dt varchar(23) DEFAULT NULL COMMENT 创建日期,update_dt varchar(23) DEFAULT NULL COMMENT 最后修改日期,create_uid varchar(32) DEFAULT NULL COMMENT 创建人,update_uid varchar(32) DEFAULT NULL COMMENT 修改人,data_flg varchar(6) DEFAULT NULL COMMENT 是否启用,record_version bigint(20) NOT NULL,flow_status varchar(16) DEFAULT NULL COMMENT 流程状态,refresh_token_overdue_seconds bigint(20) DEFAULT NULL,account varchar(80) DEFAULT NULL COMMENT 企业账号,password varchar(200) DEFAULT NULL COMMENT 登录密码,client_name varchar(255) DEFAULT NULL COMMENT 客户端名称,access_token_overdue_seconds bigint(20) DEFAULT NULL,client_id bigint(20) DEFAULT NULL,call_back_url varchar(255) DEFAULT NULL COMMENT 回调地址,PRIMARY KEY (row_id)
) ENGINEInnoDB DEFAULT CHARSETutf8;-- ----------------------------
-- Records of comm_sso_client_app
-- ----------------------------
INSERT INTO comm_sso_client_app VALUES (qwertyuiopkmjh7890nbgfvcredsz231, null, null, null, null, 2024-11-30 11:11:11, 2024-11-30 11:11:11, system, system, 1, 0, null, null, zzyc, 123456, 众智益成, null, 1, http://localhost:8001/demo/oauth2client/callback);然后我们创建一个实体类
package org.openjweb.core.entity;import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;import java.io.Serializable;Slf4j
Data
TableName(comm_sso_client_app)
public class CommSsoClientApp implements Serializable {TableId(type IdType.ASSIGN_UUID)private String rowId;private String dataFlg;private Integer refreshTokenOverdueSeconds;private String account;private String password;private String clientName;private Integer accessTokenOverdueSeconds;private Long clientId;private String callBackUrl;private Long sortNo;TableField(fill FieldFill.INSERT)private String createDt;TableField(fill FieldFill.INSERT_UPDATE)private String updateDt;TableField(fill FieldFill.INSERT)private String createUid;TableField(fill FieldFill.INSERT_UPDATE)private String updateUid;Versionprivate Long recordVersion 0L;//因为是非空所以试着给一个初始值}创建CommSsoClientAppMapper.java
package org.openjweb.core.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.openjweb.core.entity.CommSsoClientApp;
import java.util.List;Mapper
public interface CommSsoClientAppMapper extends BaseMapperCommSsoClientApp {Select(SELECT * FROM comm_sso_client_app WHERE account #{account})CommSsoClientApp selectByAccountId(Param(account) String account) ;}开发CommSsoClientAppService
package org.openjweb.core.service;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.openjweb.core.entity.CommSsoClientApp;
import org.openjweb.core.mapper.CommSsoClientAppMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;Service
Slf4j
public class CommSsoClientAppService extends ServiceImplCommSsoClientAppMapper, CommSsoClientApp {Autowiredprivate CommSsoClientAppMapper commSsoClientAppMapper;public CommSsoClientApp selectByAccountId(String accountId){CommSsoClientApp ent this.commSsoClientAppMapper.selectByAccountId(accountId);return ent;}
}接下来再开发一个控制层的类用于测试以后也需要实现增删改查
package org.openjweb.core.api;import org.openjweb.core.entity.CommSsoClientApp;
import org.openjweb.core.service.CommSsoClientAppService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** 测试地址http://localhost:8001/demo/ssoclient/queryAccount?accountzzyc*/
RequestMapping(/demo/ssoclient)
RestController
public class CommSsoClientAppApi {Autowiredprivate CommSsoClientAppService commSsoClientAppService;RequestMapping(queryAccount)public String queryAccount(String account){CommSsoClientApp ent this.commSsoClientAppService.selectByAccountId(account);if(ent!null){return ent.getClientName();}return 没查到!;}
}访问上面代码里的测试地址可正常查询。
四、开发OAuth2服务端
4.1 配置一个资源服务器 在openjweb-sys中配置一个资源服务器 import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;//资源服务器配置
Configuration
EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter
{Overridepublic void configure(ResourceServerSecurityConfigurer resources){resources.resourceId(resource-info);}Overridepublic void configure(HttpSecurity http) throws Exception{//配置拦截接口http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().requestMatchers().antMatchers(/api/user/**).and().authorizeRequests().antMatchers(/api/user/**).authenticated();}
}
4.2 实现OAuth2的ClientDetails 在openjweb-sys中开发一个OAuth2ClientDetails实现OAuth2的ClientDetails接口
package org.openjweb.sys.config.oauth.model;import org.openjweb.core.entity.CommSsoClientApp;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.provider.ClientDetails;import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;public class OAuth2ClientDetails implements ClientDetails {private CommSsoClientApp client;public OAuth2ClientDetails(CommSsoClientApp client) {this.client client;}Overridepublic String getClientId() {return client.getAccount();}Overridepublic SetString getResourceIds() {return new HashSet();}Overridepublic boolean isSecretRequired() {return true;}Overridepublic String getClientSecret() {return new BCryptPasswordEncoder().encode(client.getPassword());}Overridepublic boolean isScoped() {return true;}Overridepublic SetString getScope() {SetString set new HashSet();set.add(read);return set;}Overridepublic SetString getAuthorizedGrantTypes() {SetString set new HashSet();set.add(authorization_code);set.add(refresh_token);return set;}Overridepublic SetString getRegisteredRedirectUri() {SetString set new HashSet();set.add(client.getCallBackUrl());return set;}Overridepublic CollectionGrantedAuthority getAuthorities() {return new HashSet();}Overridepublic Integer getAccessTokenValiditySeconds() {return client.getAccessTokenOverdueSeconds();}Overridepublic Integer getRefreshTokenValiditySeconds() {return client.getRefreshTokenOverdueSeconds();}Overridepublic boolean isAutoApprove(String s) {return true;}Overridepublic MapString, Object getAdditionalInformation() {return new HashMap();}}特别注意上面代码中如果getClientSecret()方法中这样写 return new BCryptPasswordEncoder().encode(client.getPassword());
会报这种错误There is no PasswordEncoder mapped for the id null网上查了这个报错的原因是返回的密码的前面需要有加密算法名称带{}包裹例如BCrypt的格式{bcrypt}密码所以getClientSecret()方法应这么写 return {bcrypt}new BCryptPasswordEncoder().encode(client.getPassword()); 这个问题花了好长时间才找到所以大家开发时要注意另外网上好像没找到AES的对应加密算法名所以这里可能不支持AES的加密算法表达式。 因为OAuth2有个一个ClientDetailsService接口所以还需要实现此接口的方法这个ClientDetailsService会在后面的OAuth2的认证服务类中使用另外此类使用了上面的OAuth2ClientDetails类。现在我们实现一个OAuth2ClientDetailsService
package com.xujianjie.oauth2.provider.config.auth.service;import com.xujianjie.oauth2.provider.config.auth.model.MyClientDetails;
import com.xujianjie.oauth2.provider.model.Client;
import com.xujianjie.oauth2.provider.service.ClientService;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.ClientRegistrationException;
import org.springframework.stereotype.Service;Service
public class MyClientDetailsService implements ClientDetailsService
{Autowiredprivate ClientService clientService;Overridepublic ClientDetails loadClientByClientId(String account) throws ClientRegistrationException{Client client clientService.findByAccount(account);if (client null){throw new ClientRegistrationException(企业客户未注册);}return new MyClientDetails(client);}
}4.3 实现OAuth2的认证服务配置类 现在开始开发OAuth2的认证服务配置类
package org.openjweb.sys.config.oauth;import lombok.extern.slf4j.Slf4j;
import org.openjweb.core.service.CommUserService;
import org.openjweb.sys.config.oauth.service.OAuth2ClientDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;//授权服务器配置
Configuration
EnableAuthorizationServer
Slf4j
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter
{Autowiredprivate CommUserService myUserDetailsService;Autowiredprivate OAuth2ClientDetailsService myClientDetailsService;Autowired//Qualifier(authenticationManagerBean) //authenticationManagerBean有什么区别,对应WebSecurityConfig里的Qualifier(authenticationManager) //private AuthenticationManager authenticationManager;//service企业认证Overridepublic void configure(ClientDetailsServiceConfigurer clients) throws Exception {clients.withClientDetails(myClientDetailsService);}Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {endpoints.authenticationManager(authenticationManager).userDetailsService(myUserDetailsService);}
}4.4 改造WebSecurityConfig.java 集成OAuth2需要对WebSecurityConfig.java进行改造。configure(HttpSecurity http)方法中根据application-dev.yml中的配置如果启用了OAuth2 Server则使用不同的配置另外对于JwtAuthenticationFilter这个Bean如果启用了OAuth2 Server 则不能使用所以需要对Bean增加条件注解 BeanConditionalOnExpression(${oauth2.server}false)JwtAuthenticationFilter jwtAuthenticationFilter() throws Exception {JwtAuthenticationFilter jwtAuthenticationFilter new JwtAuthenticationFilter(authenticationManager());return jwtAuthenticationFilter;}
下面是WebSecurityConfig.java的完整代码
package org.openjweb.sys.config;import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.openjweb.core.service.CommUserService;
import org.openjweb.sys.auth.security.AESPasswordEncoder;
import org.openjweb.sys.auth.security.MD5PasswordEncoder;
import org.openjweb.sys.auth.security.MyAccessDecisionManager;
import org.openjweb.sys.auth.security.MyFilterInvocationSecurityMetadataSource;
import org.openjweb.sys.entry.JwtAuthenticationEntryPoint;
import org.openjweb.sys.filter.JwtAuthenticationFilter;
import org.openjweb.sys.handler.JWTLogoutSuccessHandler;
import org.openjweb.sys.handler.JwtAccessDeniedHandler;
import org.openjweb.sys.handler.LoginFailureHandler;
import org.openjweb.sys.handler.LoginSuccessHandler;
import org.openjweb.sys.provider.MyAuthenticationProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;Slf4j
Configuration
EnableWebSecurity
RequiredArgsConstructor
EnableGlobalMethodSecurity(prePostEnabled true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {AutowiredCommUserService userDetailService;Beanpublic PasswordEncoder passwordEncoder(){return new AESPasswordEncoder();}AutowiredLoginSuccessHandler loginSuccessHandler;AutowiredLoginFailureHandler loginFailureHandler;AutowiredJwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;AutowiredJwtAccessDeniedHandler jwtAccessDeniedHandler;AutowiredJWTLogoutSuccessHandler jwtLogoutSuccessHandler;Value(${oauth2.server})private boolean isOAuth2Server false;private static final String[] ALLOW_URL_LIST {///login,/logout,/captcha,/favicon.ico,///api/jwt/**,/api/cms/**,/api/b2c/**,/api/b2b2c/**,/api/sns/**,/api/comm/**,/api/cms1/**,/api/store/**,/demo/**,/oauth/** //允许oauth认证的路径};//作用暴露AuthenticationManager给其他Bean使用BeanOverrideprotected AuthenticationManager authenticationManager() throws Exception {return super.authenticationManager();//return super.authenticationManagerBean();}//这个和上面的是什么区别能一起用吗/*BeanOverridepublic AuthenticationManager authenticationManagerBean() throws Exception{return super.authenticationManagerBean();}*/Overrideprotected void configure(HttpSecurity http) throws Exception {//下面是第二阶段整合了数据库权限控制的示例log.info(是否配置了oauth2 server:::::);log.info(String.valueOf(this.isOAuth2Server));if(this.isOAuth2Server){log.info(OAUTH2模式...........);http.formLogin()//.loginPage(/login.html).loginProcessingUrl(/login).and().authorizeRequests().antMatchers(/login.html, /img/**,/demo/**).permitAll().anyRequest().authenticated().and().csrf().disable();}else {log.info(非OAUTH2模式............);http.authorizeRequests().withObjectPostProcessor(new ObjectPostProcessorFilterSecurityInterceptor() {Overridepublic O extends FilterSecurityInterceptor O postProcess(O object) {object.setSecurityMetadataSource(cfisms());object.setAccessDecisionManager(cadm());return object;}}).and().formLogin()//先注掉这个检查oauth认证//.successHandler(loginSuccessHandler) //登录成功处理.failureHandler(loginFailureHandler) //登录失败处理.loginProcessingUrl(/login).permitAll()//.loginProcessingUrl(/demo/jwt/login).permitAll().and().logout().logoutSuccessHandler(jwtLogoutSuccessHandler)// 禁用session.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)// 配置拦截规则.and().authorizeRequests().antMatchers(ALLOW_URL_LIST).permitAll().anyRequest().authenticated()// 异常处理器.and().exceptionHandling()//接口登录模式打开这个//.authenticationEntryPoint(jwtAuthenticationEntryPoint) //这个影响登录会导致/login登录蔬菜.accessDeniedHandler(jwtAccessDeniedHandler)// 配置自定义的过滤器//这个jwtAuthenticationFilter 不加也执行了是否增加了会调整多个过滤器的执行顺序.and().addFilter(jwtAuthenticationFilter()).logout().permitAll().and().csrf().disable();}}Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {if(true){//如果自定义AuthenticationProvider 则不使用这个//auth.userDetailsService(userDetailService).passwordEncoder(aesPasswordEncoder);//auth.userDetailsService(userDetailService).passwordEncoder(new BCryptPasswordEncoder());DaoAuthenticationProvider provider new DaoAuthenticationProvider();provider.setUserDetailsService(userDetailService);provider.setPasswordEncoder(passwordEncoder());auth.authenticationProvider(provider);}else{//自定义AuthenticationProviderauth.authenticationProvider(new MyAuthenticationProvider(userDetailService));}}BeanMyAccessDecisionManager cadm() {//System.out.println(加载角色权限设置。。。。。。。。。。。。);return new MyAccessDecisionManager();}BeanMyFilterInvocationSecurityMetadataSource cfisms() {//System.out.println(加载权限设置。。。。。。。。。。。。);return new MyFilterInvocationSecurityMetadataSource();}BeanConditionalOnExpression(${oauth2.server}false)JwtAuthenticationFilter jwtAuthenticationFilter() throws Exception {JwtAuthenticationFilter jwtAuthenticationFilter new JwtAuthenticationFilter(authenticationManager());return jwtAuthenticationFilter;}
}五、OAuth2客户端开发 现在我们在openjweb-sys中开发一个客户端测试API主要实现: (1) 跳转到OAuth2 Server请求登录 2获取到授权码后在请求头增加clientID和密码向OAuth2 Server的/oauth/token请求登 录。 3OAuth2 Server重定向到Spring Security 的登录页用户登录成功后返回带access-token 的JSON。 4接下来用户可带着access-token请求获取用户详细信息接口、或者调用refreshToken刷新 token或者在本地进行客户端的Spring Security登录。 下面是代码
package org.openjweb.sys.api;import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.apache.tomcat.util.codec.binary.Base64;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestClientResponseException;
import org.springframework.web.client.RestTemplate;import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;RestController
RequestMapping(/demo/oauth2client)
Slf4j
public class Oauth2DemoApi {RequestMapping(value /login2, method RequestMethod.GET)public void thirdLogin2(HttpServletResponse response) throws IOException {//localhost:8001/demo/oauth2client/login2String url http://localhost:8001/oauth/authorize?response_typecodeclient_idzzycredirect_urihttp://localhost:8001/demo/oauth2client/callback;response.sendRedirect(url);}RequestMapping(valuecallback,method RequestMethod.GET)public JSONObject callback(String code){System.out.println(在回调中callBack中存储返回的值..............);System.out.println(得到的code:::);System.out.println(code );HttpHeaders headers new HttpHeaders();String clientId zzyc;//注意使用自己企业的ID//在请求头中设置client的ID和密码headers.add(authorization, Basic new String(Base64.encodeBase64((clientId : 123456).getBytes())));MultiValueMapString, Object params new LinkedMultiValueMap();params.add(grant_type, authorization_code);params.add(code, code);params.add(client_id, clientId);params.add(redirect_uri, http://localhost:8001/demo/oauth2client/callback);String result null;JSONObject resultJson new JSONObject();//http://localhost:8003/oauth/tokentry {log.info(oauth2请求开始..............);//result new RestTemplate().postForObject(http://localhost:8003/oauth/token, new HttpEntity(params, headers), String.class);//result new RestTemplate().postForObject(http://localhost:8003/oauth/token, new HttpEntity(params, headers), String.class);result new RestTemplate().postForObject(http://localhost:8001/oauth/token, new HttpEntity(params, headers), String.class);if (result null){System.out.println(请求oauth失败返回空................);}else{log.info(返回result:result);}JSONObject json1 JSONObject.parseObject(result);String accessToken json1.getString(access_token);String refreshToken json1.getString(refresh_token);HttpHeaders tmpHeaders new HttpHeaders();tmpHeaders.add(authorization, Bearer accessToken);try{result new RestTemplate().exchange(http://localhost:8001/api/user/info, HttpMethod.GET, new HttpEntity(tmpHeaders), String.class).getBody();log.info(返回的用户信息result::::::);log.info(result);//将第三方用户写入本系统中JSONObject json JSONObject.parseObject(result);//用户基本信息//演示refreshtokenHttpHeaders tmpHeaders2 new HttpHeaders();tmpHeaders2.add(authorization, Basic new String(Base64.encodeBase64((clientId : 123456).getBytes())));//用这个不行//tmpHeaders2.set(Authorization, Bearer accessToken);// 准备请求体参数MapString, String params1 new HashMap();params1.put(grant_type, refresh_token);//refresh_tokenparams1.put(refresh_token, refreshToken);params1.put(scope, read); //scope参数同样用于定义新的访问令牌的权限范围确保客户端只能访问其被授权的资源// 发送请求获取响应// 创建请求实体设置请求头和方法HttpEntityString requestEntity new HttpEntity(tmpHeaders2);ResponseEntityString response new RestTemplate().exchange(http://localhost:8001/oauth/token?grant_typerefresh_tokenrefresh_tokenrefreshToken,HttpMethod.POST,//不能用GETrequestEntity, //请求实体包含请求头和请求体String.class,params1 //URL中的值,没加成功);if(responsenull){log.info(response为空!!!!!);}else{log.info(response非空!!!!);}String newResult response.getBody();log.info(新获取的token:);log.info(newResult);return json;/* 向本地插入新用户...*/}catch (RestClientResponseException e){e.printStackTrace();}}catch (RestClientResponseException e){e.printStackTrace();}return resultJson;}} 测试流程 1访问http://localhost:8001/demo/oauth2client/login2 开始测试此方法将请求重定向到了OAuth2 Server http://localhost:8001/oauth/authorize?response_typecodeclient_idzzycredirect_urihttp://localhost:8001/demo/oauth2client/callback 2OAuth2自动重定向到了Spring Security登录页前后端分离模式需要考虑如何改造 输入admin密码Hello0214 然后点Sign in 登录。登录成功后浏览器的地址显示为
http://localhost:8001/demo/oauth2client/callback?codeufk81B 就是带code授权码的地址后续是在后台拿到授权码后又请求了 http://localhost:8001/oauth/token 看上面的代码请求时在头部有client:123456 client端用户名密码的authorization头请求成功后后台显示返回的数据包
result:{access_token:6d37957a-7a96-43cf-876b-67aad7977447,token_type:bearer,refresh_token:80324e85-a819-4f34-bffb-e2d1686583c2,expires_in:43199,scope:read} 然后后面演示了头部带着access_token请求OAuth2 Server的获取用户详情接口http://localhost:8001/api/user/info返回了用户信息{authorities:null,accountNonExpired:true,accountNonLocked:true,credentialsNonExpired:false,enabled:true,userId:1,rowId:1221212121ssss,loginId:admin,...} 在实际项目中可以考虑将OAuth2 Server端登录成功但本地还没有的用户自动加到本地的用户表中。另外在项目开发中经常需要重新获取token上面的代码中有调用refreshtoken重新获取token的代码 MapString, String params1 new HashMap();params1.put(grant_type, refresh_token);//refresh_tokenparams1.put(refresh_token, refreshToken);params1.put(scope, read); //scope参数同样用于定义新的访问令牌的权限范围确保客户端只能访问其被授权的资源// 发送请求获取响应// 创建请求实体设置请求头和方法HttpEntityString requestEntity new HttpEntity(tmpHeaders2);ResponseEntityString response new RestTemplate().exchange(http://localhost:8001/oauth/token?grant_typerefresh_tokenrefresh_tokenrefreshToken,HttpMethod.POST,//不能用GETrequestEntity, //请求实体包含请求头和请求体String.class,params1 //URL中的值,没加成功);
测试刷新token返回的json:
新获取的token: 2024-12-01 21:58:58.125 INFO 4576 --- [io-8001-exec-10] org.openjweb.sys.api.Oauth2DemoApi : {access_token:f0f8ae6e-8ba2-4c9c-ab60-cbb2c3db8f76,token_type:bearer,refresh_token:80324e85-a819-4f34-bffb-e2d1686583c2,expires_in:43199,scope:read}
【客户端SpringSecurity登录】 目前只是在服务器端登录拿到了access_token客户端实际还没有登录在获取用户详情后可以参考下面的代码实现本地SpringSecurity登录 AutowiredCommUserService sysUserService;AutowiredLoginSuccessHandler loginSuccessHandler;。。。。。。//在获取用户详情后String loginId json.getString(loginId);//登录用户json是上面代码获取用户详情CommUser sysUser sysUserService.selectUserByLoginId(loginId);// 构建UsernamePasswordAuthenticationToken,这里密码为null是因为提供了正确的JWT,实现自动登录UsernamePasswordAuthenticationToken token new UsernamePasswordAuthenticationToken(loginId, null, sysUserService.getUserAuthority(sysUser.getLoginId()));SecurityContextHolder.getContext().setAuthentication(token);ServletRequestAttributes sra (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();try {loginSuccessHandler.onAuthenticationSuccess(sra.getRequest(), sra.getResponse(), token);}catch(Exception ex){}
本文代码量比较大大家可从github下载完整代码GitHub - openjweb/cloud at masterOpenJWeb is a java bases low code platform. Contribute to openjweb/cloud development by creating an account on GitHub.https://github.com/openjweb/cloud/tree/master