提交 9cfc36d8 编写于 作者: 马增群

提交Oauth2.0统一认证工程

上级 6ea1d5f1
......@@ -13,20 +13,45 @@
<version>0.0.1-SNAPSHOT</version>
<name>jeeplatform-sso-oauth2</name>
<description>Demo project for Spring Boot</description>
<packaging>jar</packaging>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR4</spring-cloud.version>
<security-jwt.version>1.0.9.RELEASE</security-jwt.version>
<jjwt.version>0.9.0</jjwt.version>
</properties>
<dependencies>
<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>-->
<!--Spring Security-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!--Spring Boot Starter Web 所有demo均使用web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Security OAuth2 -->
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-jwt</artifactId>
<version>${security-jwt.version}</version>
</dependency>
<dependency>
......@@ -40,6 +65,23 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>${jjwt.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
</dependencies>
<dependencyManagement>
......
......@@ -5,7 +5,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
@SpringBootApplication
@EnableResourceServer
//@EnableResourceServer
public class JeeplatformSsoOauth2Application {
public static void main(String[] args) {
......
package org.muses.jeeplatform.oauth.config;
import org.springframework.beans.factory.annotation.Autowired;
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;
/**
* <pre>
*
* </pre>
*
* <pre>
* @author mazq
* 修改记录
* 修改后版本: 修改人: 修改日期: 2020/04/29 15:06 修改内容:
* </pre>
*/
@Configuration
@EnableAuthorizationServer
public class OAuthConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
PasswordEncoder passwordEncoder;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("jeeplatform")
.secret(passwordEncoder.encode("123"))
.autoApprove(true)
.redirectUris("http://127.0.0.1:8082/oa", "http://127.0.0.1:8082/oa")
.scopes("user")
.accessTokenValiditySeconds(7200)
.authorizedGrantTypes("authorization_code");
}
}
package org.muses.jeeplatform.oauth.config;
import org.springframework.beans.factory.annotation.Autowired;
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.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
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.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
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;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* <pre>
*
* </pre>
*
* <pre>
* @author mazq
* 修改记录
* 修改后版本: 修改人: 修改日期: 2020/04/29 15:06 修改内容:
* </pre>
*/
@Configuration
@EnableAuthorizationServer//开启授权服务
public class OAuthConfiguration extends AuthorizationServerConfigurerAdapter {
@Autowired
PasswordEncoder passwordEncoder;
@Autowired
private AuthenticationManager authenticationManager; //认证方式
@Resource(name = "userService")
private UserDetailsService userDetailsService;
private static final String CLIENT_ID = "jeeplatform";
private static final String SECRET_CHAR_SEQUENCE = "secret";
private static final String SCOPE_READ = "read";
private static final String SCOPE_WRITE = "write";
private static final String TRUST = "trust";
private static final String USER ="user";
private static final int ACCESS_TOKEN_VALIDITY_SECONDS = 1*60*60;
private static final int FREFRESH_TOKEN_VALIDITY_SECONDS = 6*60*60;
private static final String GRANT_TYPE_PASSWORD = "password"; // 密码模式授权模式
private static final String AUTHORIZATION_CODE = "authorization_code"; //授权码模式 授权码模式使用到了回调地址
private static final String REFRESH_TOKEN = "refresh_token"; //refresh token模式
private static final String IMPLICIT = "implicit"; //简化授权模式
private static final String RESOURCE_ID = "resource_id"; //指定哪些资源是需要授权验证的
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory() // 使用内存存储
.withClient(CLIENT_ID) //标记客户端id
.secret(bCryptPasswordEncoder().encode(SECRET_CHAR_SEQUENCE))//客户端安全码
.autoApprove(true) //为true 则不会被重定向到授权的页面,也不需要手动给请求授权,直接自动授权成功返回code
.redirectUris("http://127.0.0.1:8082/oa", "http://127.0.0.1:8082/oa") //重定向uri
.scopes(SCOPE_READ , SCOPE_WRITE , TRUST , USER) //允许授权范围
.accessTokenValiditySeconds(ACCESS_TOKEN_VALIDITY_SECONDS) //token 时间秒
.refreshTokenValiditySeconds(FREFRESH_TOKEN_VALIDITY_SECONDS)//刷新token 时间 秒
.authorizedGrantTypes(GRANT_TYPE_PASSWORD , AUTHORIZATION_CODE , REFRESH_TOKEN , IMPLICIT);//允许授权类型
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore()).authenticationManager(authenticationManager)
.accessTokenConverter(accessTokenConverter())
.userDetailsService(userDetailsService) //必须注入userDetailsService否则根据refresh_token无法加载用户信息
.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST,HttpMethod.OPTIONS) //支持GET POST 请求获取token
.reuseRefreshTokens(true) //开启刷新token
.tokenServices(tokenServices());
}
/**
* 认证服务器的安全配置
*
* @param security
* @throws Exception
*/
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security
.realm(RESOURCE_ID)
.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()") //isAuthenticated():排除anonymous isFullyAuthenticated():排除anonymous以及remember-me
.allowFormAuthenticationForClients(); //允许表单认证 这段代码在授权码模式下会导致无法根据code 获取token 
}
@Bean
public JwtAccessTokenConverter accessTokenConverter(){
JwtAccessTokenConverter converter = new JwtAccessTokenConverter(){
@Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
String grantType = authentication.getOAuth2Request().getGrantType();
//只有如下两种模式才能获取到当前用户信息
if(AUTHORIZATION_CODE.equals(grantType) || GRANT_TYPE_PASSWORD.equals(grantType)) {
String userName = authentication.getUserAuthentication().getName();
// 自定义一些token 信息 会在获取token返回结果中展示出来
Map<String, Object> additionalInformation = new HashMap<>();
additionalInformation.put("user_name", userName);
additionalInformation = Collections.unmodifiableMap(additionalInformation);
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInformation);
}
OAuth2AccessToken token = super.enhance(accessToken, authentication);
return token;
}
};
converter.setSigningKey("bcrypt");
return converter;
}
@Bean
public TokenStore tokenStore() {
//基于jwt实现令牌(Access Token)
return new JwtTokenStore(accessTokenConverter());
}
@Bean
public DefaultTokenServices tokenServices() {
final DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenEnhancer(accessTokenConverter());
defaultTokenServices.setTokenStore(tokenStore());
defaultTokenServices.setSupportRefreshToken(true);
defaultTokenServices.setAccessTokenValiditySeconds((int) TimeUnit.DAYS.toSeconds(30)); // 30天
return defaultTokenServices;
}
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
}
package org.muses.jeeplatform.oauth.config;
import org.muses.jeeplatform.oauth.filter.SimpleCORSFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
import javax.annotation.Resource;
/**
* <pre>
*
* </pre>
*
* <pre>
* @author mazq
* 修改记录
* 修改后版本: 修改人: 修改日期: 2020/04/30 15:58 修改内容:
* </pre>
*/
@Configuration
@EnableWebSecurity
//@EnableGlobalMethodSecurity(prePostEnabled = true)
//@EnableAutoConfiguration(exclude = {
// org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration.class })
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private SimpleCORSFilter simpleCORSFilter;
@Resource(name = "userService")
private UserDetailsService userDetailsService;
private static final String SECRET_CHAR_SEQUENCE = "secret";
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Autowired
public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
//auth.inMemoryAuthentication()
//.withUser("casuser")
//.password(bCryptPasswordEncoder().encode("Mellon"));
auth.userDetailsService(userDetailsService)
.passwordEncoder(bCryptPasswordEncoder());
auth.parentAuthenticationManager(authenticationManagerBean());
}
@Override
public void configure(WebSecurity web) throws Exception {
//解决静态资源被拦截的问题
web.ignoring().antMatchers("/assets/**");
web.ignoring().antMatchers("/favicon.ico");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable() //关闭跨域保护
.authorizeRequests()
.anyRequest().authenticated() //所有请求都需要通过认证
.and()
.httpBasic() //Basic登录
.and()
.formLogin()
.loginPage("/login")
.permitAll();
//http.addFilterBefore(simpleCORSFilter, SecurityContextPersistenceFilter.class);
}
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
}
package org.muses.jeeplatform.oauth.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.Date;
/**
* <pre>
*
* </pre>
*
* <pre>
* @author mazq
* 修改记录
* 修改后版本: 修改人: 修改日期: 2020/04/30 15:24 修改内容:
* </pre>
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserDto implements Serializable {
/** 用户Id**/
private int id;
/** 用户名**/
private String username;
/** 用户密码**/
private String password;
/** 手机号**/
private String phone;
/** 性别**/
private String sex;
/** 邮件**/
private String email;
/** 备注**/
private String mark;
/** 用户级别**/
private String rank;
/** 最后一次时间**/
private Date lastLogin;
/** 登录ip**/
private String loginIp;
/** 图片路径**/
private String imageUrl;
/** 注册时间**/
private Date regTime;
/** 账号是否被锁定**/
private Boolean locked = Boolean.FALSE;
/** 权限**/
private String rights;
}
package org.muses.jeeplatform.oauth.filter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Slf4j
@Component
public class SimpleCORSFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
httpServletRequest.setCharacterEncoding("utf-8");
httpServletResponse.setCharacterEncoding("utf-8");
httpServletResponse.setHeader("Content-Type", "application/json");
httpServletResponse.setHeader("Access-Control-Allow-Origin", "*");//允许所有域名访问
httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS");//允许的访问方式
httpServletResponse.setHeader("Access-Control-Allow-Headers", "x-requested-with,content-type,Authorization");
httpServletResponse.setHeader("Access-Control-Request-Headers", "x-requested-with,content-type,Accept,Authorization");
httpServletResponse.setHeader("Access-Control-Request-Method", "GET,POST,PUT,DELETE,OPTIONS");
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
}
\ No newline at end of file
package org.muses.jeeplatform.oauth.service;
import lombok.extern.slf4j.Slf4j;
import org.muses.jeeplatform.oauth.dto.UserDto;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* <pre>
*
* </pre>
*
* <pre>
* @author mazq
* 修改记录
* 修改后版本: 修改人: 修改日期: 2020/04/30 15:15 修改内容:
* </pre>
*/
@Slf4j
@Service("userService")
public class UserDetailsServiceImpl implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserDto user = new UserDto();
// if(user == null){
// log.info("登录用户[{}]没注册!",username);
// throw new UsernameNotFoundException("登录用户["+username + "]没注册!");
// }
return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), getAuthority());
}
private List getAuthority() {
//return Arrays.asList(new SimpleGrantedAuthority("admin"));
return Arrays.asList(Collections.emptyList());
}
}
server:
port:
8888
\ No newline at end of file
8888
# JWT 配置
jwt:
# 存放Token的Header Key
header: Authorization
# 密匙key
secret: mySecret
# 过期时间 单位秒 7天后过期 604800
expiration: 3600
# 自定义token 前缀字符
tokenHead: Bearer-
# 超时时间 单位秒
access_token: 3600
# 刷新token时间 单位秒
refresh_token: 3600
route:
authentication:
path: login/entry
refresh: oauth/refresh
register: login/account
# 不需要拦截的url地址
#mySecurity:
# exclude:
# antMatchers: /oauth/**,/login,/home
\ No newline at end of file
package org.muses.jeeplatform.oauth;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class JeeplatformSsoOauth2ApplicationTests {
@Test
void contextLoads() {
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册