transfer auth2
2021/11/13 23:14:26
本文主要是介绍transfer auth2,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
代码:
AuthorizationServerConfig
@Configuration
@EnableAuthorizationServer
class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
//数据源,用于从数据库获取数据进行认证操作,测试可以从内存中获取
@Autowired
private DataSource dataSource;
//jwt令牌转换器
@Autowired
private JwtAccessTokenConverter jwtAccessTokenConverter;
//SpringSecurity 用户自定义授权认证类
@Autowired
UserDetailsService userDetailsService;
//授权认证管理器
@Autowired
AuthenticationManager authenticationManager;
//令牌持久化存储接口
@Autowired
TokenStore tokenStore;
@Autowired
private CustomUserAuthenticationConverter customUserAuthenticationConverter;
/*** * 客户端信息配置 * @param clients * @throws Exception */ @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.jdbc(dataSource).clients(clientDetails()); /* clients.inMemory() .withClient("changgou") //客户端id .secret("changgou") //秘钥 .redirectUris("http://localhost") //重定向地址 .accessTokenValiditySeconds(3600) //访问令牌有效期 .refreshTokenValiditySeconds(3600) //刷新令牌有效期 .authorizedGrantTypes( "authorization_code", //根据授权码生成令牌 "client_credentials", //客户端认证 "refresh_token", //刷新令牌 "password") //密码方式认证 .scopes("app"); //客户端范围,名称自定义,必填*/ } /*** * 授权服务器端点配置 * @param endpoints * @throws Exception */ @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints.accessTokenConverter(jwtAccessTokenConverter) .authenticationManager(authenticationManager)//认证管理器 .tokenStore(tokenStore) //令牌存储 .userDetailsService(userDetailsService); //用户信息service } /*** * 授权服务器的安全配置 * @param oauthServer * @throws Exception */ @Override public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception { oauthServer.allowFormAuthenticationForClients() .passwordEncoder(new BCryptPasswordEncoder()) .tokenKeyAccess("permitAll()") .checkTokenAccess("isAuthenticated()"); } //读取密钥的配置 @Bean("keyProp") public KeyProperties keyProperties(){ return new KeyProperties(); } @Resource(name = "keyProp") private KeyProperties keyProperties; //客户端配置 @Bean public ClientDetailsService clientDetails() { return new JdbcClientDetailsService(dataSource); } @Bean @Autowired public TokenStore tokenStore(JwtAccessTokenConverter jwtAccessTokenConverter) { return new JwtTokenStore(jwtAccessTokenConverter); }
JwtAccessTokenConverter
/****
* JWT令牌转换器
* @param customUserAuthenticationConverter
* @return
*/
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter(CustomUserAuthenticationConverter customUserAuthenticationConverter) {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
KeyPair keyPair = new KeyStoreKeyFactory(
keyProperties.getKeyStore().getLocation(), //证书路径 changgou.jks
keyProperties.getKeyStore().getSecret().toCharArray()) //证书秘钥 changgouapp
.getKeyPair(
keyProperties.getKeyStore().getAlias(), //证书别名 changgou
keyProperties.getKeyStore().getPassword().toCharArray()); //证书密码 changgou
converter.setKeyPair(keyPair);
//配置自定义的CustomUserAuthenticationConverter
DefaultAccessTokenConverter accessTokenConverter = (DefaultAccessTokenConverter) converter.getAccessTokenConverter();
accessTokenConverter.setUserTokenConverter(customUserAuthenticationConverter);
return converter;
}
}
@Component
public class CustomUserAuthenticationConverter extends DefaultUserAuthenticationConverter {
@Autowired UserDetailsService userDetailsService; @Override public Map<String, ?> convertUserAuthentication(Authentication authentication) { LinkedHashMap response = new LinkedHashMap(); String name = authentication.getName(); response.put("username", name); Object principal = authentication.getPrincipal(); UserJwt userJwt = null; if(principal instanceof UserJwt){ userJwt = (UserJwt) principal; }else{ //refresh_token默认不去调用userdetailService获取用户信息,这里我们手动去调用,得到 UserJwt UserDetails userDetails = userDetailsService.loadUserByUsername(name); userJwt = (UserJwt) userDetails; } response.put("name", userJwt.getName()); response.put("id", userJwt.getId()); //公司 response.put("compy", "songsi"); if (authentication.getAuthorities() != null && !authentication.getAuthorities().isEmpty()) { response.put("authorities", AuthorityUtils.authorityListToSet(authentication.getAuthorities())); } return response; }
}
UserDetailsServiceImpl
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired ClientDetailsService clientDetailsService;
@Autowired
private UserFeign userFeign;
/**** * 自定义授权认证 * @param username * @return * @throws UsernameNotFoundException */ @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { //取出身份,如果身份为空说明没有认证 Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); //没有认证统一采用httpbasic认证,httpbasic中存储了client_id和client_secret,开始认证client_id和client_secret if(authentication==null){ ClientDetails clientDetails = clientDetailsService.loadClientByClientId(username); if(clientDetails!=null){ //秘钥 String clientSecret = clientDetails.getClientSecret(); //静态方式 //return new User(username,new BCryptPasswordEncoder().encode(clientSecret), AuthorityUtils.commaSeparatedStringToAuthorityList("")); //数据库查找方式 return new User(username,clientSecret, AuthorityUtils.commaSeparatedStringToAuthorityList("")); } } if (StringUtils.isEmpty(username)) { return null; } //根据用户名查询用户信息 //String pwd = new BCryptPasswordEncoder().encode("szitheima"); String pwd = userFeign.findByUsername(username).getData().getPassword(); //创建User对象 授予权限.GOODS_LIST SECKILL_LIST String permissions = "goods_list,seckill_list"; UserJwt userDetails = new UserJwt(username,pwd,AuthorityUtils.commaSeparatedStringToAuthorityList(permissions)); //userDetails.setComy(songsi); return userDetails; } public static void main(String[] args) { String zhangsan = new BCryptPasswordEncoder().encode("zhangsan"); System.out.println(zhangsan); }
}
WebSecurityConfig
@Configuration
@EnableWebSecurity
@Order(-1)
class WebSecurityConfig extends WebSecurityConfigurerAdapter {
/*** * 忽略安全拦截的URL * @param web * @throws Exception */ @Override public void configure(WebSecurity web) throws Exception { web.ignoring().antMatchers( "/user/login", "/user/logout","/oauth/login","/css/**","/data/**","/fonts/**","/img/**","/js/**"); } /*** * 创建授权管理认证对象 * @return * @throws Exception */ @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { AuthenticationManager manager = super.authenticationManagerBean(); return manager; } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { super.configure(auth); } /*** * 采用BCryptPasswordEncoder对密码进行编码 * @return */ @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } /**** * * @param http * @throws Exception */ @Override public void configure(HttpSecurity http) throws Exception { http.csrf().disable() .httpBasic() //启用Http基本身份验证 .and() .formLogin() //启用表单身份验证 .loginPage("/oauth/login") .loginProcessingUrl("/user/login") .and() .authorizeRequests() //限制基于Request请求访问 .anyRequest() .authenticated(); //其他请求都需要经过验证 }
}
AuthController
/*****
-
@Author: www.itheima
-
@Date: 2019/7/7 16:42
-
@Description: com.changgou.oauth.controller
****/
@RestController
@RequestMapping(value = “/userx”)
public class AuthController {//客户端ID
@Value("${auth.clientId}")
private String clientId;//秘钥
@Value("${auth.clientSecret}")
private String clientSecret;//Cookie存储的域名
@Value("${auth.cookieDomain}")
private String cookieDomain;//Cookie生命周期
@Value("${auth.cookieMaxAge}")
private int cookieMaxAge;@Autowired
AuthService authService;@PostMapping("/login")
public Result login(String username, String password) {
if(StringUtils.isEmpty(username)){
throw new RuntimeException(“用户名不允许为空”);
}
if(StringUtils.isEmpty(password)){
throw new RuntimeException(“密码不允许为空”);
}
//申请令牌
AuthToken authToken = authService.login(username,password,clientId,clientSecret);//用户身份令牌 String access_token = authToken.getAccessToken(); //将令牌存储到cookie saveCookie(access_token); return new Result(true, StatusCode.OK,"登录成功!");
}
/***
- 将令牌存储到cookie
- @param token
*/
private void saveCookie(String token){
HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
CookieUtil.addCookie(response,cookieDomain,"/",“Authorization”,token,cookieMaxAge,false);
}
}
LoginRedirectController
@Controller
@RequestMapping("/oauth")
public class LoginRedirectController {
@RequestMapping("/login") public String login(String From, Model model) { model.addAttribute("from",From); return "login"; }
}
AuthServiceImpl
@Service
public class AuthServiceImpl implements AuthService {
@Autowired private LoadBalancerClient loadBalancerClient; @Autowired private RestTemplate restTemplate; /*** * 授权认证方法 * @param username * @param password * @param clientId * @param clientSecret * @return */ @Override public AuthToken login(String username, String password, String clientId, String clientSecret) { //申请令牌 AuthToken authToken = applyToken(username,password,clientId, clientSecret); if(authToken == null){ throw new RuntimeException("申请令牌失败"); } return authToken; } /**** * 认证方法 * @param username:用户登录名字 * @param password:用户密码 * @param clientId:配置文件中的客户端ID * @param clientSecret:配置文件中的秘钥 * @return */ private AuthToken applyToken(String username, String password, String clientId, String clientSecret) { //选中认证服务的地址 ServiceInstance serviceInstance = loadBalancerClient.choose("user-auth"); if (serviceInstance == null) { throw new RuntimeException("找不到对应的服务"); } //获取令牌的url String path = serviceInstance.getUri().toString() + "/oauth/token"; //定义body MultiValueMap<String, String> formData = new LinkedMultiValueMap<>(); //授权方式 formData.add("grant_type", "password"); //账号 formData.add("username", username); //密码 formData.add("password", password); //定义头 MultiValueMap<String, String> header = new LinkedMultiValueMap<>(); header.add("Authorization", httpbasic(clientId, clientSecret)); //指定 restTemplate当遇到400或401响应时候也不要抛出异常,也要正常返回值 restTemplate.setErrorHandler(new DefaultResponseErrorHandler() { @Override public void handleError(ClientHttpResponse response) throws IOException { //当响应的值为400或401时候也要正常响应,不要抛出异常 if (response.getRawStatusCode() != 400 && response.getRawStatusCode() != 401) { super.handleError(response); } } }); Map map = null; try { //http请求spring security的申请令牌接口 ResponseEntity<Map> mapResponseEntity = restTemplate.exchange(path, HttpMethod.POST,new HttpEntity<MultiValueMap<String, String>>(formData, header), Map.class); //获取响应数据 map = mapResponseEntity.getBody(); } catch (RestClientException e) { throw new RuntimeException(e); } if(map == null || map.get("access_token") == null || map.get("refresh_token") == null || map.get("jti") == null) { //jti是jwt令牌的唯一标识作为用户身份令牌 throw new RuntimeException("创建令牌失败!"); } //将响应数据封装成AuthToken对象 AuthToken authToken = new AuthToken(); //访问令牌(jwt) String accessToken = (String) map.get("access_token"); //刷新令牌(jwt) String refreshToken = (String) map.get("refresh_token"); //jti,作为用户的身份标识 String jwtToken= (String) map.get("jti"); authToken.setJti(jwtToken); authToken.setAccessToken(accessToken); authToken.setRefreshToken(refreshToken); return authToken; } /*** * base64编码 * @param clientId * @param clientSecret * @return */ private String httpbasic(String clientId,String clientSecret){ //将客户端id和客户端密码拼接,按“客户端id:客户端密码” String string = clientId+":"+clientSecret; //进行base64编码 byte[] encode = Base64Utils.encode(string.getBytes()); return "Basic "+new String(encode); }
}
LoginServiceImpl
@Service
public class LoginServiceImpl implements LoginService {
@Autowired private RestTemplate restTemplate; @Autowired private LoadBalancerClient loadBalancerClient; @Override public AuthToken login(String username, String password, String clientId, String clientSecret, String grandType) { //1.定义url (申请令牌的url) //参数 : 微服务的名称spring.appplication指定的名称 ServiceInstance choose = loadBalancerClient.choose("user-auth"); String url =choose.getUri().toString()+"/oauth/token"; //2.定义头信息 (有client id 和client secr) MultiValueMap<String,String> headers = new LinkedMultiValueMap<>(); headers.add("Authorization","Basic "+Base64.getEncoder().encodeToString(new String(clientId+":"+clientSecret).getBytes())); //3. 定义请求体 有授权模式 用户的名称 和密码 MultiValueMap<String,String> formData = new LinkedMultiValueMap<>(); formData.add("grant_type",grandType); formData.add("username",username); formData.add("password",password); //4.模拟浏览器 发送POST 请求 携带 头 和请求体 到认证服务器 /** * 参数1 指定要发送的请求的url * 参数2 指定要发送的请求的方法 PSOT * 参数3 指定请求实体(包含头和请求体数据) */ HttpEntity<MultiValueMap> requestentity = new HttpEntity<MultiValueMap>(formData,headers); ResponseEntity<Map> responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestentity, Map.class); //5.接收到返回的响应(就是:令牌的信息) Map body = responseEntity.getBody(); //封装一次. AuthToken authToken = new AuthToken(); //访问令牌(jwt) String accessToken = (String) body.get("access_token"); //刷新令牌(jwt) String refreshToken = (String) body.get("refresh_token"); //jti,作为用户的身份标识 String jwtToken= (String) body.get("jti"); authToken.setJti(jwtToken); authToken.setAccessToken(accessToken); authToken.setRefreshToken(refreshToken); //6.返回 return authToken; } public static void main(String[] args) { byte[] decode = Base64.getDecoder().decode(new String("Y2hhbmdnb3UxOmNoYW5nZ291Mg==").getBytes()); System.out.println(new String(decode)); }
}
public interface AuthService {
/*** * 授权认证方法 */ AuthToken login(String username, String password, String clientId, String clientSecret);
}
public interface LoginService {
/**
* 模拟用户的行为 发送请求 申请令牌 返回
* @param username
* @param password
* @param clientId
* @param clientSecret
* @param grandType
* @return
*/
AuthToken login(String username, String password, String clientId, String clientSecret, String grandType);
}
AuthToken
public class AuthToken implements Serializable{
//令牌信息 String accessToken; //刷新token(refresh_token) String refreshToken; //jwt短令牌 String jti; public String getAccessToken() { return accessToken; } public void setAccessToken(String accessToken) { this.accessToken = accessToken; } public String getRefreshToken() { return refreshToken; } public void setRefreshToken(String refreshToken) { this.refreshToken = refreshToken; } public String getJti() { return jti; } public void setJti(String jti) { this.jti = jti; }
}
CookieUtil
public class CookieUtil {
/** * 设置cookie * * @param response * @param name cookie名字 * @param value cookie值 * @param maxAge cookie生命周期 以秒为单位 */ public static void addCookie(HttpServletResponse response, String domain, String path, String name, String value, int maxAge, boolean httpOnly) { Cookie cookie = new Cookie(name, value); cookie.setDomain(domain); cookie.setPath(path); cookie.setMaxAge(maxAge); cookie.setHttpOnly(httpOnly); response.addCookie(cookie); } /** * 根据cookie名称读取cookie * @param request * @return map<cookieName,cookieValue> */ public static Map<String,String> readCookie(HttpServletRequest request, String ... cookieNames) { Map<String,String> cookieMap = new HashMap<String,String>(); Cookie[] cookies = request.getCookies(); if (cookies != null) { for (Cookie cookie : cookies) { String cookieName = cookie.getName(); String cookieValue = cookie.getValue(); for(int i=0;i<cookieNames.length;i++){ if(cookieNames[i].equals(cookieName)){ cookieMap.put(cookieName,cookieValue); } } } } return cookieMap; }
}
OAuthApplication
@SpringBootApplication
@EnableDiscoveryClient
@MapperScan(basePackages = “com.changgou.auth.dao”)
@EnableFeignClients(basePackages = {“com.changgou.user.feign”})
public class OAuthApplication {
public static void main(String[] args) { SpringApplication.run(OAuthApplication.class,args); } @Bean(name = "restTemplate") public RestTemplate restTemplate() { return new RestTemplate(); }
}
Pom.xml
<?xml version="1.0" encoding="UTF-8"?>
changgou-parent
com.changgou
1.0-SNAPSHOT
4.0.0
changgou-user-oauth
OAuth2.0认证环境搭建
<dependencies> <!--查询数据库数据--> <dependency> <groupId>com.changgou</groupId> <artifactId>changgou-common-db</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-data</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-oauth2</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>com.changgou</groupId> <artifactId>changgou-service-user-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <!--thymleaf的依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> </dependencies>
application.yml
server:
port: 9001
spring:
application:
name: user-auth
redis:
host: 192.168.211.132
port: 6379
password:
jedis:
pool:
max-active: 8
max-idle: 8
min-idle: 0
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://192.168.211.132:3306/changgou_oauth?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowMultiQueries=true&serverTimezone=UTC
username: root
password: 123456
main:
allow-bean-definition-overriding: true
thymeleaf:
cache: false
eureka:
instance:
prefer-ip-address: true
client:
service-url:
defaultZone: http://127.0.0.1:7001/eureka
auth:
ttl: 3600 #token存储到redis的过期时间
clientId: changgou
clientSecret: changgou
cookieDomain: localhost
cookieMaxAge: -1
encrypt:
key-store:
location: classpath:/changgou.jks
secret: changgou
alias: changgou
password: changgou
脚本:
申请授权码
GET
http://localhost:9001/oauth/authorize?client_id=changgou&response_type=code&scop=app&redirect_uri=http://localhost
根据授权码获取token
POST
http://localhost:9001/oauth/token
Authorization: username password (Basic Auth)
form-data:
grant_type authorization_code
Code kKghj4
redirect_uri http://localhost
刷新令牌:
POST
http://localhost:9001/oauth/token?grant_type=refresh_token&refresh_token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY29wZSI6WyJhcHAiXSwiYXRpIjoiMjNmYTQwOGEtYzkyMi00NDdmLTk3OTktNjY2NjEzNjEwNTM5IiwibmFtZSI6bnVsbCwiaWQiOm51bGwsImV4cCI6MTYzNDQ4OTA4MCwiYXV0aG9yaXRpZXMiOlsic2Vja2lsbF9saXN0IiwiZ29vZHNfbGlzdCJdLCJqdGkiOiI0ZjU3MWU5ZS05MGMxLTQ0YzMtOTI1ZS05OTRjODQ4MmQ2OWMiLCJjbGllbnRfaWQiOiJjaGFuZ2dvdSIsInVzZXJuYW1lIjoic3ppdGhlaW1hIn0.MdkCkvQidZ2kJ6YC45-JDtr1sMSRmlEAZH5Vj3IkgLxvLFf5mktPqYMMFLS5K5yut53G5gBRCy792ZYbkC0sT-y5tHAnpGrTwLJPG6ZUI8dr5t2UotX4xDv_zlo4DQiUfmG2kBD8hKQeBaa6Y5WdWndfq11sNmdwZzFIBkGsgT-I15IXtx3UEL5y-kMQ30xpBJG_OlGE9y8RCi1H0Xa-kEPNVvkqYWwawW9mBgasH57yeYTEWYhgVCmYmLV3YZdQOu58JqwHKcFeUwUSya77m2Rr157uOZjxTk3tSoBtUAqLivJNU8XmRAxT5UIU4S5Sv7Egzm3uHjL7LWLKuCZ40g
令牌校验:
POST
http://localhost:9001/oauth/check_token?token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY29wZSI6WyJhcHAiXSwibmFtZSI6bnVsbCwiaWQiOm51bGwsImV4cCI6MTYzNDQ4OTA4MCwiYXV0aG9yaXRpZXMiOlsic2Vja2lsbF9saXN0IiwiZ29vZHNfbGlzdCJdLCJqdGkiOiIyM2ZhNDA4YS1jOTIyLTQ0N2YtOTc5OS02NjY2MTM2MTA1MzkiLCJjbGllbnRfaWQiOiJjaGFuZ2dvdSIsInVzZXJuYW1lIjoic3ppdGhlaW1hIn0.BlU5X5ZkJWq0X-AT1Qjg3eRkhvBvtgqpkW6twqn1sM0diXxjlxoZsOJspqHDFlbg2nrgv0uGMohEOhd8-1tLTZyttCTCqRaEkIsx-8u-vQmhmk9WqguGTjXKWZZhYAiXhlfg4SntMiAHYGmSyhoXAaH8GKifQb6Kyp-ChSAvAnwKzkQKNoMdXVTNyGlEn70ZCXw8gMwyJT9DH1Tr3o-sjyZ9Cq6uk4xMC7u-rypgJp2DsedCQo9wh5QH4PlD-QzqJq9FWsPFJnLptDYcXg9wIPRzmQnT33QqG9pDMHo2gCXuIa3oZlTylWcwFyt9ERohafZcbGvQQemp5kwEgQnjDQ
http://localhost:9001/oauth/token
Post
Formdata:
grant_type password
Username szitheima
Password szitheima
这篇关于transfer auth2的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-12-22项目:远程温湿度检测系统
- 2024-12-21《鸿蒙HarmonyOS应用开发从入门到精通(第2版)》简介
- 2024-12-21后台管理系统开发教程:新手入门全指南
- 2024-12-21后台开发教程:新手入门及实战指南
- 2024-12-21后台综合解决方案教程:新手入门指南
- 2024-12-21接口模块封装教程:新手必备指南
- 2024-12-21请求动作封装教程:新手必看指南
- 2024-12-21RBAC的权限教程:从入门到实践
- 2024-12-21登录鉴权实战:新手入门教程
- 2024-12-21动态权限实战入门指南