赞
踩

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.5.5</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>oauth-learn2</artifactId> <version>0.0.1-SNAPSHOT</version> <name>oauth-learn2</name> <properties> <java.version>1.8</java.version> </properties> <dependencies> <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.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <!--security end--> <!--数据库依赖 begin--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <!--数据库依赖 end--> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-jwt</artifactId> <version>1.0.10.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security.oauth.boot</groupId> <artifactId>spring-security-oauth2-autoconfigure</artifactId> <version>2.3.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
spring.application.name=oauth-authorizationServer
server.port=8083
spring.datasource.url = jdbc:mysql://localhost:3306/testoauth?useUnicode=true
spring.datasource.username=root
spring.datasource.password=ylx123
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.main.allow-bean-definition-overriding=true
package com.example.oauthlearn2.bean; import lombok.Data; /** * @Description 请描述下该类是做什么的 * @Author <a href="mailto:yuanlx@smartdot.com.cn">袁凌霄</a> * @Date 2021/9/25 11:13 * @Verson 1.0 **/ @Data public class UserBean { private Long id; private String userName; private String password; }
package com.example.oauthlearn2.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; 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; import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer; import org.springframework.security.oauth2.provider.ClientDetailsService; import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices; import org.springframework.security.oauth2.provider.code.InMemoryAuthorizationCodeServices; import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices; import org.springframework.security.oauth2.provider.token.DefaultTokenServices; import org.springframework.security.oauth2.provider.token.TokenEnhancerChain; import org.springframework.security.oauth2.provider.token.TokenStore; import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; import java.util.Arrays; /** * @Description 请描述下该类是做什么的 * @Author <a href="mailto:yuanlx@smartdot.com.cn">袁凌霄</a> * @Date 2021/9/25 11:14 * @Verson 1.0 **/ @Configuration @EnableAuthorizationServer // 配置授权服务。 public class AuthorizationServer extends AuthorizationServerConfigurerAdapter { @Autowired private JwtAccessTokenConverter accessTokenConverter; @Autowired // 授权码服务 private AuthorizationCodeServices authorizationCodeServices; @Autowired // 认证管理 private AuthenticationManager authenticationManager; @Autowired // 令牌管理服务 private AuthorizationServerTokenServices authorizationServerTokenServices; @Autowired // 令牌存储策略 private TokenStore tokenStore; @Autowired // 客户端详情服务,也就是configure(ClientDetailsServiceConfigurer clients)方法 private ClientDetailsService clientDetailsService; @Autowired // 加密方式 private PasswordEncoder passwordEncoder; // 用来配置客户端详情服务 @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { // 这里是第三方合作用户的客户id,秘钥的配置 // 使用in-memory存储 clients.inMemory() // client_id,用户账号 .withClient(OauthCanstant.clientId) // 客户端密钥 .secret(new BCryptPasswordEncoder().encode(OauthCanstant.secret)) // 资源列表,资源标识 .resourceIds(OauthCanstant.resourceIds) // 授权类型(4种) .authorizedGrantTypes(OauthCanstant.authorizedGrantTypes) // 客戶端允许的授权范围 .scopes(OauthCanstant.scopes) // false跳转到授权页面,让用户点击授权,如果是true,相当于自动点击授权,就不跳转授权页面 .autoApprove(OauthCanstant.autoApprove)// // 加上验证回调地址,返回授权码信息 .redirectUris(OauthCanstant.redirectUris); } // 令牌管理服务 @Bean public AuthorizationServerTokenServices authorizationServerTokenServices() { DefaultTokenServices service = new DefaultTokenServices(); service.setClientDetailsService(clientDetailsService); service.setSupportRefreshToken(true);// 支持刷新 service.setTokenStore(tokenStore);// 令牌存储 // 令牌增强 TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain(); tokenEnhancerChain.setTokenEnhancers(Arrays.asList(accessTokenConverter)); service.setTokenEnhancer(tokenEnhancerChain); service.setAccessTokenValiditySeconds(OauthCanstant.accessTokenValiditySeconds); // 令牌默认有效期2小时 service.setRefreshTokenValiditySeconds(OauthCanstant.refreshTokenValiditySeconds); // 刷新令牌默认有效期3天 return service; } @Override // 用来配置令牌(token)的访问端点 public void configure(AuthorizationServerEndpointsConfigurer endpoints) { endpoints // 指定认证管理器 .authenticationManager(authenticationManager) // 授权码模式需要 .authorizationCodeServices(authorizationCodeServices) // 令牌管理服务 .tokenServices(authorizationServerTokenServices) // jwt格式Token .accessTokenConverter(accessTokenConverter) // 允许post提交 .allowedTokenEndpointRequestMethods(HttpMethod.POST); } @Bean // 授权码服务器 public AuthorizationCodeServices authorizationCodeServices() { // 授权码模式的授权码采用内存方式存储 return new InMemoryAuthorizationCodeServices(); } @Override // 用来配置令牌端点的安全约束,拦截规则 public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { security // 提供公有密匙的端点,如果你使用JWT令牌的话, 允许 .tokenKeyAccess(OauthCanstant.permitAll) // oauth/check_token:用于资源服务访问的令牌解析端点,允许 .checkTokenAccess(OauthCanstant.permitAll) // 表单认证,申请令牌 .allowFormAuthenticationForClients(); } }
package com.example.oauthlearn2.config; /** * @Description 请描述下该类是做什么的 * @Author <a href="mailto:yuanlx@smartdot.com.cn">袁凌霄</a> * @Date 2021/9/25 11:15 * @Verson 1.0 **/ public interface OauthCanstant { String clientId = "c1"; String secret = "secret"; String resourceIds = "res1"; String authorizedGrantTypes = "password"; String scopes = "all"; boolean autoApprove = false; String redirectUris = "http://www.baidu.com"; String permitAll = "permitAll()"; // 令牌默认有效期2小时 int accessTokenValiditySeconds = 7200; // 刷新令牌默认有效期3天 int refreshTokenValiditySeconds = 259200; // 对称秘钥,资源服务器使用该秘钥来验证 String SIGNING_KEY = "uaa123"; }
package com.example.oauthlearn2.config; import org.springframework.beans.factory.annotation.Autowired; 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; import org.springframework.security.oauth2.provider.token.TokenStore; /** * @Description 请描述下该类是做什么的 * @Author <a href="mailto:yuanlx@smartdot.com.cn">袁凌霄</a> * @Date 2021/9/25 11:15 * @Verson 1.0 **/ @Configuration @EnableResourceServer public class ResouceServerConfig extends ResourceServerConfigurerAdapter { @Autowired // 令牌存储策略 private TokenStore tokenStore; @Override public void configure(ResourceServerSecurityConfigurer resources) { resources // 资源 id .resourceId(OauthCanstant.resourceIds) // // 令牌服务 .tokenStore(tokenStore) .stateless(true); } @Override public void configure(HttpSecurity http) throws Exception { http .authorizeRequests().antMatchers("/**") // 所有的访问,授权访问都要是all,和认证服务器的授权范围一一对应 .access("#oauth2.hasScope('"+OauthCanstant.scopes+"')") //去掉防跨域攻击 .and().csrf().disable() //session管理 .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS); } }
package com.example.oauthlearn2.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.oauth2.provider.token.TokenStore; import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; /** * @Description 请描述下该类是做什么的 * @Author <a href="mailto:yuanlx@smartdot.com.cn">袁凌霄</a> * @Date 2021/9/25 11:16 * @Verson 1.0 **/ @Configuration public class TokenConfig { @Bean public TokenStore tokenStore() { // JWT令牌存储方案 return new JwtTokenStore(accessTokenConverter()); } @Bean public JwtAccessTokenConverter accessTokenConverter() { JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); converter.setSigningKey(OauthCanstant.SIGNING_KEY); // 对称秘钥,资源服务器使用该秘钥来验证 return converter; } }
package com.example.oauthlearn2.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.web.builders.HttpSecurity; 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; /** * @Description 请描述下该类是做什么的 * @Author <a href="mailto:yuanlx@smartdot.com.cn">袁凌霄</a> * @Date 2021/9/25 11:16 * @Verson 1.0 **/ @Configuration // @EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true) public class WebSecurityConfig extends WebSecurityConfigurerAdapter { // 认证管理器 @Override @Bean public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } // 密码编码器 @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } // 安全拦截机制 @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().anyRequest().authenticated()// 所有其他请求必须认证通过 .and().formLogin().loginPage("/login").successForwardUrl("/login-success")// 自定义登录成功的页面地址 .permitAll().and().logout().permitAll().and()// 会话管理 .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);// 会话管理 } }
package com.example.oauthlearn2.controller; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * @Description 请描述下该类是做什么的 * @Author <a href="mailto:yuanlx@smartdot.com.cn">袁凌霄</a> * @Date 2021/9/25 11:17 * @Verson 1.0 **/ @RestController public class LoginController { @RequestMapping(value = "/login-success") public String loginSuccess() { return getUsername() + " login-success 登录成功"; } /** * 测试资源1 * * @return */ @GetMapping(value = "/admin/p1") // @PreAuthorize("hasAuthority('p1')")//拥有p1权限才可以访问 public String r1() { return " /admin/p1 " + getUsername() + "访问资源1"; } /** * 测试资源2 * * @return */ @GetMapping(value = "/user/p2") // @PreAuthorize("hasAuthority('p2')")//拥有p2权限才可以访问 public String r2() { return "/user/p2 " + getUsername() + "访问资源2"; } // 获取当前用户信息 private String getUsername() { String username = null; // 当前认证通过的用户身份 Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); // 用户身份 Object principal = authentication.getPrincipal(); if (principal == null) { username = "匿名"; } if (principal instanceof UserDetails) { UserDetails userDetails = (UserDetails) principal; username = userDetails.getUsername(); } else { username = principal.toString(); } return username; } }
package com.example.oauthlearn2.dao; import com.example.oauthlearn2.bean.UserBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; import java.util.List; /** * @Description 请描述下该类是做什么的 * @Author <a href="mailto:yuanlx@smartdot.com.cn">袁凌霄</a> * @Date 2021/9/25 11:17 * @Verson 1.0 **/ @Repository public class UserDao { @Autowired JdbcTemplate jdbcTemplate; // 根据账号查询用户信息 public UserBean getUserByUsername(String username) { String sql = "select * from user where user_name = ?"; // 连接数据库查询用户 List<UserBean> list = jdbcTemplate.query(sql, new Object[] { username }, new BeanPropertyRowMapper<>(UserBean.class)); if (list != null && list.size() == 1) { return list.get(0); } return null; } }
package com.example.oauthlearn2.service; import com.example.oauthlearn2.bean.UserBean; import com.example.oauthlearn2.dao.UserDao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; /** * @Description 请描述下该类是做什么的 * @Author <a href="mailto:yuanlx@smartdot.com.cn">袁凌霄</a> * @Date 2021/9/25 11:18 * @Verson 1.0 **/ @Service public class SpringDataUserDetailsService implements UserDetailsService { @Autowired UserDao userDao; // 根据账号查询用户信息, // 通过@Service将SpringDataUserDetailsService注入容器,通过UserDetailsService接口表明该类的类型是UserDetailsService @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { // 将来连接数据库根据账号查询用户信息 UserBean bean = userDao.getUserByUsername(username); if (bean == null) { // 如果用户查不到,返回null,由provider来抛出异常 return null; } // 添加p1权限,权限是随便加的,这里已经没有意义了 UserDetails userDetails = User.withUsername(bean.getUserName()).password(bean.getPassword()).authorities("p1") .build(); return userDetails; } }
http://localhost:8083/oauth/token?client_id=c1&client_secret=secret&grant_type=password&username=admin&password=admin

http://localhost:8083/admin/p1
头部信息中添加 Authorization,值为:“Bearer ” + token

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。