1.创建工程
创建父工程SpringAuth
修改pom文件
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.2</version>
<relativePath/>
</parent>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.4.2</spring-boot.version>
<spring-cloud.version>2020.0.1</spring-cloud.version>
<spring-cloud-alibaba.version>2021.1</spring-cloud-alibaba.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
创建子工程
分别创建cloud-auth用于授权认证,cloud-comm用于存放公共类,cloud-service用于存放业务,cloud-gateway用于存放网关
cloud-comm
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
server:
port: 8081
spring:
application:
name: auth-comm
cloud:
nacos:
discovery:
server-addr: localhost:8848
cloud-auth
<dependencies>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.3.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.example</groupId>
<artifactId>cloud-comm</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-jwt</artifactId>
<version>1.1.0.RELEASE</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.18</version>
</dependency>
</dependencies>
server:
port: 8082
spring:
application:
name: auth-auth
cloud:
nacos:
discovery:
server-addr: localhost:8848
config:
server-addr: localhost:8848
file-extension: yaml
2.编辑工程
cloud-auth授权码模式
package com.cloud.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/oauth/**","/").permitAll() //oauth的路径全部放行
.anyRequest().authenticated() //其他接口需要认证
.and()
.formLogin().permitAll(); //放行登陆接口
http.csrf().disable().cors();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.passwordEncoder(passwordEncoder())
.withUser("yzx")
.password(passwordEncoder().encode("123456"))
.roles("ADMIN");
}
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
}
package com.cloud.config;
import org.springframework.context.annotation.Configuration;
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 javax.annotation.Resource;
@Configuration
@EnableAuthorizationServer //认证服务器
public class OauthConfig extends AuthorizationServerConfigurerAdapter {
@Resource
private PasswordEncoder passwordEncoder;
//第三方客户端的信息
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()//表示配置第三方客户端信息
.withClient("admin")//设置的第三方客户端选项client_id,第三方登陆的名字
.secret(passwordEncoder.encode("aa"))//对应oauth协议一个属性,client_secret,第三方登陆密码
.authorizedGrantTypes("authorization_code","refresh_token")//对应授权的模式是什么,第二个参数代表可以获取刷新的token
/*
authorization_code 授权码模式
password 密码模式
implicit 简单模式
client_credentials 客户端模式
*/
.redirectUris("http://localhost:8082")//从哪里拿到code
.autoApprove(true)//是否自动授权
.scopes("all");//授权的范围
/*
/oauth/authoriz 授权端点
/oauth/token 获取token
/oauth/check 检验token
*/
}
}
package com.cloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class AuthMain {
public static void main(String[] args) {
SpringApplication.run(AuthMain.class, args);
}
}
进行启动
localhost:8082/oauth/authorize?response_type=code&client_id=admin&scope=all
因为/路径没有内容,所以会404页面,但在url地址栏会携带一个code参数,将该值拿到,该值为授权码
然后通过该授权码来生成token,
localhost:8082/oauth/token?grant_type=authorization_code
&code=VvxTRs&client_id=admin&redirect_url=http://localhost:8082&scope=all
第一个参数表示授权的模式是什么,第二个是授权码,第三个是第三方登陆的用户是谁,第四个是把token返回到哪里
使用postman进行厕所,生成token,需要携带着第三方信息
access_token:生成的token
token_type:token的类型
refresh_token:该token的有效期是access_token有效期的两倍
expires_in:有效期
总结:搭建授权认证服务器,在oauth配置文件种设置授权模式,访问授权站点得到授权码,通过授权码获得token
cloud-auth简单模式
修改oauth配置类
访问
localhost:8082/oauth/authorize?response_type=token&client_id=admin&scope=all
登陆得到地址
http://localhost:8082/#access_token=ac55179f-0e70-4a34-ad27-29506cc719b2&token_type=bearer&expires_in=43199
地址即包括了token
cloud-auth客户端模式
cloud-auth密码模式
修改SecurityConfig类,重写authenticationManager()方法,并注入到spring容器
@Override
@Bean
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
修改OauthConfig类,将AuthenticationManager注入进来,并重写configure()方法
@Resource
private AuthenticationManager authenticationManager;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager);
}
访问时需要携带第三方用户名和密码以及security登陆的用户名和密码‘
3.生成token
修改cloud-auth
修改config类
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints.authenticationManager(authenticationManager);
endpoints.tokenStore(getTokenStore());
endpoints.accessTokenConverter(getConverter());//生成jwt,解析jwt
}
@Bean
public TokenStore getTokenStore(){
return new JwtTokenStore(getConverter());
}
/*
解析,生成jwt
*/
@Bean
public JwtAccessTokenConverter getConverter() {
JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
jwtAccessTokenConverter.setSigningKey("yzx");
return jwtAccessTokenConverter;
}
使用密码模式访问获取token
配置放行路径
配置config类
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.allowFormAuthenticationForClients()
.checkTokenAccess("permitAll()")//放行oauth/check_token路径
.tokenKeyAccess("permitAll()");//放行oauth/token路径
}
然后重新使用密码模式获取token,在授权使用无授权方式进行获取,也可以获取到token
校验token
将刚刚获取到的token进行校验,使用get方式
localhost:8082/oauth/check_token?token=传入token值
4.资源服务器
在cloud-service工程下创建service-product工程,添加启动类,依赖,配置文件
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.3.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
</dependency>
</dependencies>
server:
port: 8083
spring:
application:
name: service-product
cloud:
nacos:
discovery:
server-addr: localhost:8848
创建控制层和配置类
@RestController
@RequestMapping("/product")
public class ProductController {
@GetMapping("/info")
@PreAuthorize("hasRole('ADMIN')")
public String info(){
return "hello world";
}
}
@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true,jsr250Enabled = true)
public class ProductConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()//配置所有路径都需要认证
.and()
.csrf().disable();
}
@Bean
public TokenStore getTokenStore(){
return new JwtTokenStore(getConverter());
}
/*
解析,生成jwt
*/
@Bean
public JwtAccessTokenConverter getConverter() {
JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
jwtAccessTokenConverter.setSigningKey("yzx");
return jwtAccessTokenConverter;
}
}
携带token访问
security默认获取请求头中的token值,key为Authorization,值为beare的token
bearer拼接token值
登陆成功,返回token给前端
cloud-auth,修改security配置类
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/oauth/**","/","/login").permitAll() //oauth的路径全部放行
.anyRequest().authenticated() //其他接口需要认证
.and()
.formLogin().permitAll(); //放行登陆接口
http.csrf().disable().cors();
http.formLogin().loginProcessingUrl("/login").successHandler(getSuccessHandler());
}
@Bean
public AuthenticationSuccessHandler getSuccessHandler() {
return (httpServletRequest, httpServletResponse, authentication) -> {
HttpRequest post = HttpUtil.createPost("http://localhost:8082/oauth/token");
post.form("grant_type","password");
post.form("client_id","admin");
post.form("client_secret","aa");
post.form("username",httpServletRequest.getParameter("username"));
post.form("password",httpServletRequest.getParameter("password"));
HttpResponse execute = post.execute();//执行
Token token = JSON.parseObject(execute.body(), Token.class);
ReturnData(httpServletResponse,new Result(200,"登陆成功",token));
};
}
private void ReturnData(HttpServletResponse response, Result result){
response.setContentType("application/json;charset=utf-8");
try {
PrintWriter writer = response.getWriter();
writer.println(result.getData());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.75</version>
</dependency>
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Token {
private String access_token;
private Integer expires_in;
private String scope;
private String jti;
}
在成功登陆后,调用successHadler方法,进行发送请求获取token,然后将token返回给前端