单点登录微服务阿里下
调用服务,通关认证服务之后,feign调用其他服务
Oauth2规范 oauth2定义了一种认证授权协议,一种规范,此规范中定义了四种类型的角色: 1)资源有者(User) 2)认证授权服务器(jt-auth) 3)资源服务器(jt-resource) 4)客户端应用(jt-ui) 同时,在这种协议中规定了认证授权时的几种模式: 1)密码模式 (基于用户名和密码进行认证) 2)授权码模式(就是我们说的三方认证:QQ,微信,微博,。。。。)…
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
加上依赖以后,项目启动时会显示一串登录密码,如图
默认登录地址localhost:8071
配置一下
server:
port: 8071
spring:
application:
name: spa-auth
cloud:
nacos:
discovery:
server-addr: localhost:8848
config:
server-addr: localhost:8848
登陆逻辑
有两种: 1.基于cookies 2.基于redis 流程:
令牌生成对象配置 TokenStore
借助JWT(Json Web Token-是一种json格式 这是暗号,auth服务和所调用的资源服务都需要
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
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;
@Configuration
public class TokenConfig {
private String SIGNING_KEY= "auth";
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter());
}
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter(){
JwtAccessTokenConverter converter=new JwtAccessTokenConverter();
converter.setSigningKey(SIGNING_KEY);
return converter;
}
}
配置一下
server:
port: 8071
spring:
application:
name: sca-auth
cloud:
nacos:
discovery:
server-addr: localhost:8848
config:
server-addr: localhost:8848
auth服务
第一 认证授权服务器的核心配 AuthorizationServerConfigurerAdapter
package com.jt.auth.config;
import lombok.AllArgsConstructor;
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.core.userdetails.UserDetailsService;
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.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;
@AllArgsConstructor
@Configuration
@EnableAuthorizationServer
public class Oauth2Config extends AuthorizationServerConfigurerAdapter {
private AuthenticationManager authenticationManager;
private TokenStore tokenStore;
private JwtAccessTokenConverter jwtAccessTokenConverter;
private PasswordEncoder passwordEncoder;
private UserDetailsService userDetailsService;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService)
.allowedTokenEndpointRequestMethods(HttpMethod.POST,HttpMethod.GET)
.tokenServices(tokenService());
}
@Bean
public AuthorizationServerTokenServices tokenService(){
DefaultTokenServices services=new DefaultTokenServices();
services.setSupportRefreshToken(true);
services.setTokenStore(tokenStore);
TokenEnhancerChain chain=new TokenEnhancerChain();
chain.setTokenEnhancers(
Arrays.asList(jwtAccessTokenConverter));
services.setTokenEnhancer(chain);
services.setAccessTokenValiditySeconds(3600);
services.setRefreshTokenValiditySeconds(3600*72);
return services;
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("gateway-client")
.secret(passwordEncoder.encode("123456"))
.scopes("all")
.authorizedGrantTypes("password","refresh_token");
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security
.tokenKeyAccess("permitAll()")
.checkTokenAccess("permitAll()")
.allowFormAuthenticationForClients();
}
}
第二 安全配置类 WebSecurityConfigurerAdapter
SecurityConfig配置类,添加登录成功或失败的处理逻辑,
package com.jt.auth.config;
import com.fasterxml.jackson.databind.ObjectMapper;
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public BCryptPasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationManager authenticationManagerBean()
throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.authorizeRequests().anyRequest().permitAll();
http.formLogin()
.successHandler(successHandler())
.failureHandler(failureHandler());
}
@Bean
public AuthenticationSuccessHandler successHandler(){
return (request,response,authentication) ->{
Map<String,Object> map=new HashMap<>();
map.put("state",200);
map.put("message","login ok");
writeJsonToClient(response,map);
};
}
@Bean
public AuthenticationFailureHandler failureHandler(){
return (request,response, e)-> {
Map<String,Object> map=new HashMap<>();
map.put("state",500);
map.put("message","login failure");
writeJsonToClient(response,map);
};
}
private void writeJsonToClient(HttpServletResponse response,
Object object) throws IOException {
String jsonStr=new ObjectMapper().writeValueAsString(object);
PrintWriter writer = response.getWriter();
writer.println(jsonStr);
writer.flush();
}
@Bean
public AuthenticationManager authenticationManagerBean()
throws Exception {
return super.authenticationManagerBean();
}
}
资源服务
第三 资源服务令牌解析 ResourceServerConfigurerAdapter
spring security应用中底层会借助UserDetailService对象获取数据库信息,并进行封装,最后返回给认证管理器,完成认证操作
package cn.jjj.resource.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
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;
import org.springframework.security.web.access.AccessDeniedHandler;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Autowired
private TokenStore tokenStore;
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.tokenStore(tokenStore);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.exceptionHandling()
.accessDeniedHandler(accessDeniedHandler());
http.authorizeRequests().anyRequest().permitAll();
}
public AccessDeniedHandler accessDeniedHandler() {
return (request, response, e) -> {
Map<String, Object> map = new HashMap<>();
map.put("state", HttpServletResponse.SC_FORBIDDEN);
map.put("message", "没有访问权限,请联系管理员");
response.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=utf-8");
PrintWriter out=response.getWriter();
String result=
new ObjectMapper().writeValueAsString(map);
out.println(result);
out.flush();
};
}
}
第四 权限控制
访问此方法需要具备的权限
@PreAuthorize("hasAuthority('sys:res:create')")
@PostMapping("/upload/")
public String uploadFile(MultipartFile uploadFile) throws IOException {
...
}
|