如今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 就能夠正常訪問了