您好,登錄后才能下訂單哦!
小編給大家分享一下Springboot Oauth2 Server搭建Oauth2認證服務的示例,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
介紹
這里我將介紹兩個部分
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表由我們自己控制,其他表由框架控制
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/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'); 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', '張三', 'admin', '123456', '13712345678', 'MALE', '2018-12-03 17:57:12'); INSERT INTO `sys_user` VALUES ('2', '李四', 'user', '123456', '13812345678', 'UNKNOWN', '2018-12-03 17: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 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 + "%"); } }
添加登錄攔截
@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(); } }
添加登錄表單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">用戶名</label> <input class="form-control" type="text" name="username" id="username" value="user" placeholder="賬號" required> <label for="password" class="sr-only">密碼</label> <input class="form-control" type="password" name="password" id="password" value="123456" placeholder="密碼" required> <button class="btn btn-lg btn-primary btn-block" type="submit">登錄</button> </form> </div>
Oauth3 server Config
@Configuration @EnableAuthorizationServer public class OAuth3AuthorizationConfig extends AuthorizationServerConfigurerAdapter { @Autowired private Environment env; @Autowired private AuthenticationManager authenticationManager; /** * 自定義授權頁面 */ @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()); // 支持password grant type endpoints.authenticationManager(authenticationManager); } @Override public void configure(AuthorizationServerSecurityConfigurer oauthServer) { 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
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<OAuth3AccessToken> getAccessTokenExtractor() { return OAuth3AccessTokenJsonExtractor.instance(); } @Override public OAuth30Service createService(OAuthConfig config) { return new AiwanService(this, config); } }
OAuth30Service
public class AiwanService extends OAuth30Service { 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; } }
獲取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"; /** * 為防止CSRF跨站攻擊,每次請求STATE的值應該不同,可以放入Session! * 由于都是localhost測試,所以session無法保持,用一個固定值。 */ 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 OAuth30Service 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!"); } OAuth3AccessToken accessToken = aiwanApi.getAccessToken(code); request.getSession().setAttribute(SESSION_KEY_ACCESS_TOKEN, accessToken); return "profile"; } }
以上是“Springboot Oauth2 Server搭建Oauth2認證服務的示例”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。