如今Spring boot 极大的简化了 Spring Framework 应用程序的配置,经过简单的依赖配置便可实现程序的基本安全。html
首先咱们先了解一下 oauth 2.0java
OAuth 2.0 的规范能够参考 : RFC 6749git
OAuth 是一个开放标准,容许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用。目前,OAuth 的最新版本为 2.0web
OAuth 容许用户提供一个令牌,而不是用户名和密码来访问他们存放在特定服务提供者的数据。每个令牌受权一个特定的网站(例如,视频编辑网站)在特定的时段(例如,接下来的2小时内)内访问特定的资源(例如仅仅是某一相册中的视频)。这样,OAuth 容许用户受权第三方网站访问他们存储在另外的服务提供者上的信息,而不须要分享他们的访问许可或他们数据的全部内容。spring
在咱们的系统中咱们须要 添加依赖库。sql
· spring-boot-starter-web数据库
· spring-boot-starter-security安全
· spring-boot-starter-web服务器
· spring-security-jwt session
· spring-security-oauth2
配置的主要目录结构是这样的
首先配置Spring boot 的配置文件 application.properties
security.oauth2.resource.filter-order=3 security.signing-key=MaYzkSjmkzPC57L security.security-name=fmanager security.jwt.client-id=testjwtclientid security.jwt.client-secret=XY7kmzoNzl100 security.jwt.client-role=ADMIN_USER security.jwt.grant-type=password security.jwt.scope-read=read security.jwt.scope-write=write security.jwt.resource-ids=testjwtresourceid #须要的是上面部分 # LOGGING logging.level.org.springframework.web=DEBUG logging.level.main.java.com.fmanager = DEBUG spring.datasource.url=jdbc:postgresql://localhost:5432/fmanager spring.datasource.username=xxxxx spring.datasource.password=xxxx mybatis.config-locations=classpath:mybatis/mybatis-config.xml mybatis.mapper-locations=classpath:mybatis/mapper/*.xml
安全配置,
@Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfig extends WebSecurityConfigurerAdapter { @Value("${security.signing-key}") private String signingKey; @Value("${security.security-name}") private String securityRealm; @Resource private UserDetailsService userDetailsService; @Bean @Override protected AuthenticationManager authenticationManager() throws Exception { return super.authenticationManager(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService) .passwordEncoder(new BCryptPasswordEncoder()); } @Override protected void configure(HttpSecurity http) throws Exception { http .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .httpBasic() .realmName(securityRealm) .and() .csrf() .disable().authorizeRequests().antMatchers("/oauth/token").permitAll(); //$NON-NLS-1$ } @Bean public JwtAccessTokenConverter accessTokenConverter() { JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); converter.setSigningKey(signingKey); return converter; } @Bean public TokenStore tokenStore() { return new JwtTokenStore(accessTokenConverter()); } @Bean @Primary //Making this primary to avoid any accidental duplication with another token service instance of the same name public DefaultTokenServices tokenServices() { DefaultTokenServices defaultTokenServices = new DefaultTokenServices(); defaultTokenServices.setTokenStore(tokenStore()); defaultTokenServices.setSupportRefreshToken(true); return defaultTokenServices; } }
受权服务器配置
@Configuration @EnableAuthorizationServer public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { @Value("${security.jwt.client-id}") private String clientId; @Value("${security.jwt.client-secret}") private String clientSecret; @Value("${security.jwt.grant-type}") private String grantType; @Value("${security.jwt.scope-read}") private String scopeRead; @Value("${security.jwt.scope-write}") private String scopeWrite = "write"; //$NON-NLS-1$ @Value("${security.jwt.resource-ids}") private String resourceIds; @Autowired private TokenStore tokenStore; @Autowired private JwtAccessTokenConverter accessTokenConverter; @Autowired private AuthenticationManager authenticationManager; @Autowired private PasswordEncoder passwordEncoder; @Override public void configure(ClientDetailsServiceConfigurer configurer) throws Exception { configurer.inMemory().withClient(clientId).secret(passwordEncoder.encode(clientSecret)) .authorizedGrantTypes(grantType).scopes(scopeRead, scopeWrite).resourceIds(resourceIds); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { TokenEnhancerChain enhancerChain = new TokenEnhancerChain(); enhancerChain.setTokenEnhancers(Arrays.asList(accessTokenConverter)); endpoints.tokenStore(tokenStore).accessTokenConverter(accessTokenConverter).tokenEnhancer(enhancerChain) .authenticationManager(authenticationManager); } @Bean private static DelegatingPasswordEncoder passwordEncoder() { String idForEncode = "bcrypt"; //$NON-NLS-1$ Map<String, PasswordEncoder> encoderMap = new HashMap<>(); encoderMap.put(idForEncode, new BCryptPasswordEncoder()); return new DelegatingPasswordEncoder(idForEncode, encoderMap); } }
资源服务器配置
@Configuration @EnableResourceServer public class ResourceServerConfig extends ResourceServerConfigurerAdapter { @Autowired private ResourceServerTokenServices tokenServices; @Value("${security.jwt.resource-ids}") private String resourceIds; @Override public void configure(ResourceServerSecurityConfigurer resources) throws Exception { resources.resourceId(resourceIds).tokenServices(tokenServices); } @Override public void configure(HttpSecurity http) throws Exception { http .requestMatchers() .and() .authorizeRequests() .antMatchers("/**").authenticated(); //$NON-NLS-1$ } }
配置基本完成, 链接数据库的配置也很简单。 在application.properties中添加mybastis 配置以及spring 链接配置
spring.datasource.url=jdbc:postgresql://localhost:5432/fmanager spring.datasource.username=xxxxx spring.datasource.password=xxxx mybatis.config-locations=classpath:mybatis/mybatis-config.xml mybatis.mapper-locations=classpath:mybatis/mapper/*.xml
写对应mapper 就能够了
好比:
@Mapper public interface UserDAO { public User findById(long id); public User findByUserName(String name); }
好,先写一个测试Controller
@RestController @RequestMapping("/test") public class TestController { @Autowired private UserServcie userService; @RequestMapping(value="/greeting",method = RequestMethod.GET) public String greeting() { System.out.println(userService.findById(1)); return "Hello"; } }
用rest client 访问就会看到
没有权限。
咱们这里使用用户名密码获取token
获取这个token 是记得要加
Content-Type:application/x-www-form-urlencoded authorization: Basic dGVzdGp3dGNsaWVudGlkOlhZN2ttem9OemwxMDA=
这个authorization 是经过 以前的client_id 和client_secret base64 获得的。
获得这个token,
而后咱们再访问测试controller 的时候带上这个token 就能够正常访问了