目錄
一、SpringSeurity的基礎(chǔ)操作
1、引入主要依賴
2、加密器
3、實現(xiàn)自定義登錄邏輯
4、訪問限制
5、自定義異常處理?
6、通過注解的方式配置訪問控制
二、Auth2認證方案
1、什么是Auth2認證
2、Oauth2最常用的授權(quán)模式?
3、依賴引入
4、添加配置類
5、測試
6、存在到Redis里,后續(xù)推薦使用JWT
三、JWT認證機制
1、JWT的組成
2、依賴引入
3、生成JWT的測試
4、解析JWT
5、自定義聲明
四、SpringSecurityOauth2整合JWT
1、添加配置類
2、Jwt的解析
五、SpringSecurityOauth2實現(xiàn)單點登錄
1、添加對應(yīng)配置
一、SpringSeurity的基礎(chǔ)操作
1、引入主要依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
此時我們在啟動項目時會發(fā)現(xiàn)對于的頁面都需要登錄才能訪問!默認用戶名、密碼是user,密碼是控制臺啟動時打印的密碼。
2、加密器
官方推薦使用BCryptPasswordEncoder這是一個基于Hash單向加密的加密類
@Test
public void contextLoads(){
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
//密碼加密
String encode = bCryptPasswordEncoder.encode("123");
System.out.println(encode);
System.out.println("==========================");
//密碼匹配,匹配成功返回true,否則返回false
boolean matches = bCryptPasswordEncoder.matches("123", encode);
System.out.println(matches);
}
打印結(jié)果:
?在項目使用時一般將其放到Spring容器中
@Configuration
public class SecurityConfig {
@Bean
public PasswordEncoder getPw(){
return new BCryptPasswordEncoder();
}
}
3、實現(xiàn)自定義登錄邏輯
實現(xiàn)SpringSecurity里的UserDetailsService接口的LoadUserByUsername方法便可以實現(xiàn)自定義登錄邏輯。以下代碼將實現(xiàn)用戶名為admin,密碼為123的登錄。一旦使用了自定義登錄邏輯,原本的user和打印的password登錄將不再生效。此時,通過admin 123便可登錄。
對于登出SpringSecurity也提供了一個/logout的接口。
SpringSecurity框架以為我們提供了一個需要username和passsword參數(shù)的登錄接口/login 的post請求,需要登錄時框架調(diào)用的便是該接口。
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//查詢數(shù)據(jù)庫判斷用戶名是否操作,如果不存在就會拋出UsernameNotFoundException異常
if (!"admin".equals(username)) {
throw new UsernameNotFoundException("用戶名不存在!");
}
//2、把查詢出來的密碼(注冊時已經(jīng)加密過)進行解析,或者直接把密碼放入構(gòu)造方法
String password = passwordEncoder.encode("123");
return new User(username, password, AuthorityUtils.commaSeparatedStringToAuthorityList("admin,normal,ROLE_abc"));
}
}
4、訪問限制
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder getPw() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
//授權(quán)認證
http.authorizeRequests()
//error.html不需要被認證
.antMatchers("/error.html").permitAll()
//login.html不需要被認證
.antMatchers("/login.html").permitAll()
//指定角色訪問
.antMatchers("/main.html").hasRole("abc")
//指定權(quán)限訪問
.antMatchers("/main.html").hasAuthority("admin")
//多個權(quán)限都可訪問
.antMatchers("/main.html").hasAnyAuthority("admin,normal")
//多個角色都可以訪問
.antMatchers("/main.html").hasAnyRole("ABC,abc")
//通過指定ip地址進行訪問,注意這里的ip與localhost轉(zhuǎn)換的ip是不一樣的,線上一般為服務(wù)器ip
.antMatchers("/main.html").hasIpAddress("127.0.0.1")
//所有請求都必須被認證,必須登錄之后被訪問
.anyRequest().authenticated();
//關(guān)閉csrf防護
http.csrf().disable();
}
}
在訪問限制配置時,我們只需要集成WebSecurityConfigurerAdapter配置類configure(HttpSecurity http)方法即可。
多個角色也類似:注意角色這里不要加前綴ROLE_
?對應(yīng)之前服務(wù)實現(xiàn)類的權(quán)限和角色:
5、自定義異常處理?
首先添加異常處理類實現(xiàn)AccessDeniedHandler接口的handle方法,handle方法里可自定義處理SpringSecurity的403等異常的處理。
@Component
public class MyAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
//設(shè)置響應(yīng)狀態(tài)碼
httpServletResponse.setStatus(HttpServletResponse.SC_FORBIDDEN);
httpServletResponse.setHeader("Content-Type", "application/json;charset=utf-8");
PrintWriter writer = httpServletResponse.getWriter();
writer.write("{\"status\":\"error\",\"msg\":\"權(quán)限不足,請聯(lián)系管理員\"}");
writer.flush();
writer.close();
}
}
之后在SpringSecurity配置類里添加如下:
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//注入異常處理類
@Autowired
private MyAccessDeniedHandler myAccessDeniedHandler;
......
@Override
protected void configure(HttpSecurity http) throws Exception {
......
//異常處理的配置
http.exceptionHandling()
.accessDeniedHandler(myAccessDeniedHandler);
}
}
當權(quán)限不足報403時,這里會調(diào)用我們自定義的方法:
6、通過注解的方式配置訪問控制
?角色控制訪問:注意這里的ROLE_前綴不能去
其他類開啟注解@EnableGlobalMethodSecurity(securedEnabled = true)
?控制類里添加@Secured(角色名)注解進行角色訪問控制
?當用戶有ROLE_abC角色時會被允許訪問,否則會報500錯誤!
使用@PreAuthorize注解來進行訪問控制
類似的,啟動類里的參數(shù)不同而已:
進行角色訪問控制:@PreAuthorize("hasRole('abc')")? //此時,有無ROLE_前綴都是可以被訪問到的。要注意的時配置類里的hasRole方法是不允許以ROLE_前綴開頭的這里有些差別。
同時也可用于權(quán)限控制訪問:@PreAuthorize("hasAuthority('admin')")
二、Auth2認證方案
1、什么是Auth2認證
2、Oauth2最常用的授權(quán)模式?
3、依賴引入
使用Oauth2時我們在SpringSecurity的依賴上添加如下依賴:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
4、添加配置類
(1)授權(quán)模式的配置類如下
SpringSecuirty的配置類:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder getPw() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/oauth/**","/login/**","/logout/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().permitAll();
}
}
Oauth2的授權(quán)服務(wù)器配置:
@Configuration
@EnableAuthorizationServer //開啟授權(quán)服務(wù)器
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
//配置client-id
.withClient("admin")
//配置client-secret
.secret(passwordEncoder.encode("112233"))
//配置訪問token的有效期
// .accessTokenValiditySeconds(3600)
//配置redirect_uri,用于授權(quán)成功后跳轉(zhuǎn)
.redirectUris("http://www.baidu.com")
//配置申請的權(quán)限范圍
.scopes("all")
//配置grant_type,表示授權(quán)類型
.authorizedGrantTypes("authorization_code");
}
}
Oauth2的資源服務(wù)器的配置類:
@Configuration
@EnableResourceServer //開啟資源服務(wù)器
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.requestMatchers()
.antMatchers("/user/**");
}
}
密碼模式的配置類如下:
SpringSecurity配置類:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder getPw() {
return new BCryptPasswordEncoder();
}
//用于密碼認證
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception{
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/oauth/**","/login/**","/logout/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().permitAll();
}
}
授權(quán)服務(wù)器配置:
@Configuration
@EnableAuthorizationServer //開啟授權(quán)服務(wù)器
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private UserDetailsServiceImpl userDetailsService;
//使用密碼模式配置所需配置
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
//配置client-id
.withClient("admin")
//配置client-secret
.secret(passwordEncoder.encode("112233"))
//配置訪問token的有效期
// .accessTokenValiditySeconds(3600)
//配置redirect_uri,用于授權(quán)成功后跳轉(zhuǎn)
.redirectUris("http://www.baidu.com")
//配置申請的權(quán)限范圍
.scopes("all")
//配置grant_type,表示授權(quán)類型
.authorizedGrantTypes("password");
}
}
資源服務(wù)器配置:
與授權(quán)獲取token時的一樣
5、測試
啟動服務(wù)器
授權(quán)模式獲取接口資源的步驟
(1)獲取授權(quán)碼:
http://localhost:8080/oauth/authorize?response_type=code&client_id=admin&redirect_uri=http://www.baidu.com&scope=all
選擇支持認證。?
認證后記錄下這個code里的值:
(2)獲取令牌
用戶名、密碼就是授權(quán)服務(wù)器里的用戶名密碼?
填寫對應(yīng)參數(shù):
?發(fā)生請求:
(3)獲取我們自己寫的接口的數(shù)據(jù):
?選擇Bearer auth認證填入對應(yīng)token
獲取到對應(yīng)用戶信息:
?加密模式獲取資源的步驟
(1)通過授權(quán)服務(wù)獲取token
?認證配置與授權(quán)時一樣
?傳入?yún)?shù)有所不同:
通過用戶名密碼獲取到對應(yīng)token
?(2)獲取對應(yīng)接口資源,與之前授權(quán)模式獲取接口之源一樣
6、存在到Redis里,后續(xù)推薦使用JWT
?以上授權(quán)的數(shù)據(jù)是放到內(nèi)存中的實際開發(fā)過程中應(yīng)將其放到redis里
(1)添加redis依賴與配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
spring:
redis:
database: 1
host: my-server
port: 6380
password:
(2)配置類
@Configuration
public class RedisConfig {
@Autowired
private RedisConnectionFactory redisConnectionFactory;
@Bean
public TokenStore redisTokenStore(){
return new RedisTokenStore(redisConnectionFactory);
}
}
@Configuration
@EnableAuthorizationServer //開啟授權(quán)服務(wù)器
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private UserDetailsServiceImpl userDetailsService;
@Autowired
@Qualifier("redisTokenStore")
private TokenStore tokenStore;
//使用密碼模式配置所需配置
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService)
.tokenStore(tokenStore);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
//配置client-id
.withClient("admin")
//配置client-secret
.secret(passwordEncoder.encode("112233"))
//配置訪問token的有效期
// .accessTokenValiditySeconds(3600)
//配置redirect_uri,用于授權(quán)成功后跳轉(zhuǎn)
.redirectUris("http://www.baidu.com")
//配置申請的權(quán)限范圍
.scopes("all")
//配置grant_type,表示授權(quán)類型
.authorizedGrantTypes("password");
}
}
放到獲取token的接口后可以看到:數(shù)據(jù)已存在redis中去了
?
三、JWT認證機制
1、JWT的組成
JWT是由.
分割的如下三部分組成:
頭部(Header)
Header 一般由兩個部分組成:
- alg
- typ
alg
是是所使用的hash算法,如:HMAC SHA256或RSA,typ
是Token的類型,在這里就是:JWT。
{
"alg": "HS256",
"typ": "JWT"
}
然后使用Base64Url編碼成第一部分:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.<second part>.<third part>
載荷(Payload)
這一部分是JWT主要的信息存儲部分,其中包含了許多種的聲明(claims)。
Claims的實體一般包含用戶和一些元數(shù)據(jù),這些claims分成三種類型:
- reserved claims:預(yù)定義的 一些聲明,并不是強制的但是推薦,它們包括 iss (issuer), exp (expiration time), sub (subject),aud(audience) 等(這里都使用三個字母的原因是保證 JWT 的緊湊)。
- public claims: 公有聲明,這個部分可以隨便定義,但是要注意和 IANA JSON Web Token 沖突。
- private claims: 私有聲明,這個部分是共享被認定信息中自定義部分。
一個簡單的Pyload可以是這樣子的:
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
這部分同樣使用Base64Url編碼成第二部分:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.<third part>
簽名(Signature)
Signature是用來驗證發(fā)送者的JWT的同時也能確保在期間不被篡改。
在創(chuàng)建該部分時候你應(yīng)該已經(jīng)有了編碼后的Header和Payload,然后使用保存在服務(wù)端的秘鑰對其簽名,一個完整的JWT如下:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
因此使用JWT具有如下好處:
- 通用:因為json的通用性,所以JWT是可以進行跨語言支持的,像JAVA,JavaScript,NodeJS,PHP等很多語言都可以使用。
- 緊湊:JWT的構(gòu)成非常簡單,字節(jié)占用很小,可以通過 GET、POST 等放在 HTTP 的 header 中,非常便于傳輸。
- 擴展:JWT是自我包涵的,包含了必要的所有信息,不需要在服務(wù)端保存會話信息, 非常易于應(yīng)用的擴展。
2、依賴引入
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
3、生成JWT的測試
private void createToken() {
//當前系統(tǒng)時間
long now = System.currentTimeMillis();
//過期時間,1分鐘
long exp = now + 60 * 1000;
//創(chuàng)建JwtBuilder對象
JwtBuilder jwtBuilder = Jwts.builder()
//聲明的標識{“jti”:"8888"}
.setId("8888")
//主體,用戶{“sub”:"Rose"}
.setSubject("Rose")
//創(chuàng)建日期{“ita”:“xxxxxx”}
.setIssuedAt(new Date())
.signWith(SignatureAlgorithm.HS256, "xxxxxx")
//設(shè)置過期時間
.setExpiration(new Date(exp));
//獲取jwt的token
String token = jwtBuilder.compact();
System.out.println(token);
System.out.println("=======================================");
String[] split = token.split("\\.");
System.out.println(Base64Codec.BASE64.decodeToString(split[0]));
System.out.println(Base64Codec.BASE64.decodeToString(split[1]));
//無法解密
System.out.println(Base64Codec.BASE64.decodeToString(split[2]));
}
打印如下:密碼鹽一般為服務(wù)器的私鑰
4、解析JWT
private void parseJWT() {
String jwt = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4ODg4Iiwic3ViIjoiUm9zZSIsImlhdCI6MTY2NTAzNzc0MSwiZXhwIjoxNjY1MDM3ODAxfQ.jGZrGW0sYyfuatsi1xtYXI8pPflRZR4DY3BbwmSKN0M";
//解析token獲取負載中聲明的對象
Claims claims = Jwts.parser()
.setSigningKey("xxxxxx")
.parseClaimsJws(jwt)
.getBody();
System.out.println("id:" + claims.getId());
System.out.println("subject:" + claims.getSubject());
System.out.println("issuedAt:" + claims.getIssuedAt());
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("簽發(fā)時間:" + simpleDateFormat.format(claims.getIssuedAt()));
System.out.println("過期時間:" + simpleDateFormat.format(claims.getExpiration()));
System.out.println("當前時間:" + simpleDateFormat.format(new Date()));
}
?
5、自定義聲明
//自定義聲明
private void createJWTByClaims() {
//當前系統(tǒng)時間
long now = System.currentTimeMillis();
//過期時間,1分鐘
long exp = now + 60 * 1000;
//創(chuàng)建JwtBuilder對象
JwtBuilder jwtBuilder = Jwts.builder()
//聲明的標識{“jti”:"8888"}
.setId("8888")
//主體,用戶{“sub”:"Rose"}
.setSubject("Rose")
//創(chuàng)建日期{“ita”:“xxxxxx”}
.setIssuedAt(new Date())
.signWith(SignatureAlgorithm.HS256, "xxxxxx")
//設(shè)置過期時間
.setExpiration(new Date(exp))
//自定義聲明的使用
.claim("roles", "admin")
.claim("logo", "xxx.jpg");
//直接傳入Map
// .setClaims(map)
//獲取jwt的token
String token = jwtBuilder.compact();
System.out.println(token);
}
解析:
private void parseJWTClaims() {
String jwt = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4ODg4Iiwic3ViIjoiUm9zZSIsImlhdCI6MTY2NTAzODQwMiwiZXhwIjoxNjY1MDM4NDYxLCJyb2xlcyI6ImFkbWluIiwibG9nbyI6Inh4eC5qcGcifQ.fzyWQ_HG725kDoZ0zljHkIiIrO1mhl_u77r81ZeT1FA";
//解析token獲取負載中聲明的對象
Claims claims = Jwts.parser()
.setSigningKey("xxxxxx")
.parseClaimsJws(jwt)
.getBody();
System.out.println("id:" + claims.getId());
System.out.println("subject:" + claims.getSubject());
System.out.println("issuedAt:" + claims.getIssuedAt());
System.out.println("roles:" + claims.get("roles"));
System.out.println("logo:" + claims.get("logo"));
}
四、SpringSecurityOauth2整合JWT
1、添加配置類
Jwt的配置類
@Configuration
public class JwtTokenStoreConfig {
@Bean
public TokenStore jwtTokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter());
}
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter();
//配置jwt使用的密鑰
accessTokenConverter.setSigningKey("test_key");
return accessTokenConverter;
}
@Bean
public JwtTokenEnhancer jwtTokenEnhancer(){
return new JwtTokenEnhancer();
}
}
Jwt內(nèi)容增強器的配置類:
public class JwtTokenEnhancer implements TokenEnhancer {
@Override
public OAuth2AccessToken enhance(OAuth2AccessToken oAuth2AccessToken, OAuth2Authentication oAuth2Authentication) {
Map<String, Object> info = new HashMap<>();
//放入jwt里的內(nèi)容
info.put("enhance", "enhance info");
((DefaultOAuth2AccessToken) oAuth2AccessToken).setAdditionalInformation(info);
return oAuth2AccessToken;
}
}
授權(quán)服務(wù)器配置類:
@Configuration
@EnableAuthorizationServer //開啟授權(quán)服務(wù)器
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private UserDetailsServiceImpl userDetailsService;
@Autowired
@Qualifier("jwtTokenStore")
private TokenStore tokenStore;
@Autowired
private JwtAccessTokenConverter jwtAccessTokenConverter;
@Autowired
private JwtTokenEnhancer jwtTokenEnhancer;
//使用密碼模式配置所需配置
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
//配置JWT內(nèi)容增強器
TokenEnhancerChain enhancerChain = new TokenEnhancerChain();
List<TokenEnhancer> delegates = new ArrayList<>();
delegates.add(jwtTokenEnhancer);
delegates.add(jwtAccessTokenConverter);
enhancerChain.setTokenEnhancers(delegates);
endpoints.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService)
//配置存儲令牌策略
.tokenStore(tokenStore)
.accessTokenConverter(jwtAccessTokenConverter)
//配置內(nèi)容增強器
.tokenEnhancer(enhancerChain);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
//配置client-id
.withClient("admin")
//配置client-secret
.secret(passwordEncoder.encode("112233"))
//配置訪問token的有效期
.accessTokenValiditySeconds(3600)
//配置刷新令牌的有效期
.refreshTokenValiditySeconds(864000)
//配置redirect_uri,用于授權(quán)成功后跳轉(zhuǎn)
.redirectUris("http://localhost:8081/login")
//配置申請的權(quán)限范圍
.scopes("all")
//配置grant_type,表示授權(quán)類型, 刷新令牌
.authorizedGrantTypes("password","refresh_token");
}
}
重啟項目:
使用正確密碼模式的訪問接口進行測試:可以看到目前的token已經(jīng)是JWT的token了
?將此token放到官網(wǎng)解析可以看到對應(yīng)增加的信息:
2、Jwt的解析
這里需要引入之前集成JWT的依賴
添加訪問接口進行測試
@GetMapping("/getCurrentUser")
public Object getCurrentUser(Authentication authentication, HttpServletRequest request) {
String head = request.getHeader("Authorization");
String token = head.substring(head.indexOf("bearer") + 7);
return Jwts.parser()
.setSigningKey("test_key".getBytes(StandardCharsets.UTF_8))
.parseClaimsJws(token)
.getBody();
}
訪問該接口,僅需傳入請求頭Authorization和對應(yīng)的bearer+JWT即可:
?解析完畢:
3、刷新token
授權(quán)服務(wù)器配置如下:
?再次測試:可以看到刷新時的token
五、SpringSecurityOauth2實現(xiàn)單點登錄
我以之前的授權(quán)服務(wù)器作為授權(quán)服務(wù)器,現(xiàn)在在創(chuàng)建一個服務(wù)器作為單點請求登錄的服務(wù)器客戶端。依賴與授權(quán)服務(wù)器相同。
1、添加對應(yīng)配置
server:
port: 8081
servlet:
session:
# 防止Cookie沖突,沖突會導(dǎo)致登錄驗證不通過
cookie:
name: OAUTH2-CLIENT-SESSIONID01
# 授權(quán)服務(wù)器地址
oauth2-server-url: http://localhost:8080
# 與授權(quán)服務(wù)器對應(yīng)的配置
security:
oauth2:
client:
client-id: admin
client-secret: 112233
user-authorization-uri: ${oauth2-server-url}/oauth/authorize
access-token-uri: ${oauth2-server-url}/oauth/token
resource:
jwt:
key-uri: ${oauth2-server-url}/oauth/token_key
使用單點登錄時授權(quán)服務(wù)器的授權(quán)配置類:?
@Configuration
@EnableAuthorizationServer //開啟授權(quán)服務(wù)器
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private UserDetailsServiceImpl userDetailsService;
@Autowired
@Qualifier("jwtTokenStore")
private TokenStore tokenStore;
@Autowired
private JwtAccessTokenConverter jwtAccessTokenConverter;
@Autowired
private JwtTokenEnhancer jwtTokenEnhancer;
//使用密碼模式配置所需配置
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
//配置JWT內(nèi)容增強器
TokenEnhancerChain enhancerChain = new TokenEnhancerChain();
List<TokenEnhancer> delegates = new ArrayList<>();
delegates.add(jwtTokenEnhancer);
delegates.add(jwtAccessTokenConverter);
enhancerChain.setTokenEnhancers(delegates);
endpoints.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService)
//配置存儲令牌策略
.tokenStore(tokenStore)
.accessTokenConverter(jwtAccessTokenConverter)
//配置內(nèi)容增強器
.tokenEnhancer(enhancerChain);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
//配置client-id
.withClient("admin")
//配置client-secret
.secret(passwordEncoder.encode("112233"))
//配置訪問token的有效期
.accessTokenValiditySeconds(3600)
//配置刷新令牌的有效期
.refreshTokenValiditySeconds(864000)
//配置redirect_uri,用于授權(quán)成功后跳轉(zhuǎn)
.redirectUris("http://localhost:8081/login")
//自動授權(quán)配置
.autoApprove(true)
//配置申請的權(quán)限范圍
.scopes("all")
//配置grant_type,表示授權(quán)類型, 刷新令牌
.authorizedGrantTypes("password", "refresh_token", "authorization_code");
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
//獲取密鑰需要身份認證,使用單點登錄時必須配置
security.tokenKeyAccess("isAuthenticated()");
}
}
?訪問客戶端的接口:
http://localhost:8081/user/getCurrentUser
此時,會跳轉(zhuǎn)到授權(quán)服務(wù)器的登錄頁面:
登錄成功訪問到對應(yīng)接口資源:
?文章來源:http://www.zghlxwxcb.cn/news/detail-412973.html
總結(jié)到此。文章來源地址http://www.zghlxwxcb.cn/news/detail-412973.html
到了這里,關(guān)于權(quán)限管理 springboot集成springSecurity Oauth2 JWT的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!