├── README.md
├── pom.xml
└── src
├── main
├── java
│ └── com
│ │ └── unionman
│ │ └── springbootsecurityauth2
│ │ ├── SpringbootSecurityAuth2Application.java
│ │ ├── config
│ │ ├── HttpMessageConverterConfig.java
│ │ ├── OAuth2Config.java
│ │ ├── RedisConfig.java
│ │ ├── SecurityConfig.java
│ │ └── ServerConfig.java
│ │ ├── controller
│ │ └── AuthController.java
│ │ ├── domain
│ │ ├── Base.java
│ │ ├── CustomUserDetail.java
│ │ ├── Token.java
│ │ └── bean
│ │ │ └── RefreshTokenBean.java
│ │ ├── dto
│ │ ├── LoginUserDTO.java
│ │ ├── ModifyUserDTO.java
│ │ └── UserDTO.java
│ │ ├── entity
│ │ ├── Role.java
│ │ └── User.java
│ │ ├── enums
│ │ ├── ResponseEnum.java
│ │ └── UrlEnum.java
│ │ ├── handler
│ │ └── CustomAuthExceptionHandler.java
│ │ ├── repository
│ │ ├── RoleRepository.java
│ │ ├── UserRepository.java
│ │ └── base
│ │ │ └── BaseRepository.java
│ │ ├── service
│ │ ├── RoleService.java
│ │ ├── UserService.java
│ │ └── impl
│ │ │ ├── RoleServiceImpl.java
│ │ │ └── UserServiceImpl.java
│ │ ├── utils
│ │ ├── AssertUtils.java
│ │ ├── BeanUtils.java
│ │ └── RedisUtil.java
│ │ └── vo
│ │ ├── LoginUserVO.java
│ │ ├── ResponseVO.java
│ │ ├── RoleVO.java
│ │ └── UserVO.java
└── resources
│ ├── application.yml
│ └── springbootsecurityauth.sql
└── test
└── java
└── com
└── unionman
└── springbootsecurityauth2
└── SpringbootSecurityAuth2ApplicationTests.java
/README.md:
--------------------------------------------------------------------------------
1 | # springboot-security-oauth2
2 | 基于Springboot集成security、oauth2实现认证鉴权、资源管理
3 | 具体详细博文,可以参见 https://www.cnblogs.com/xiaofengxzzf/p/10733955.html
4 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 2.0.5.RELEASE
9 |
10 |
11 | com.unionman
12 | springboot-security-auth2
13 | 0.0.1-SNAPSHOT
14 | springboot-security-auth2
15 | Demo project for Spring Boot
16 |
17 |
18 | 1.8
19 |
20 |
21 |
22 |
23 | org.springframework.boot
24 | spring-boot-starter
25 |
26 |
27 | org.springframework.boot
28 | spring-boot-starter-test
29 | test
30 |
31 |
32 |
33 |
34 | org.springframework.boot
35 | spring-boot-starter-web
36 |
37 |
38 |
39 |
40 | org.springframework.boot
41 | spring-boot-starter-data-redis
42 |
43 |
44 |
45 |
46 | org.projectlombok
47 | lombok
48 |
49 |
50 |
51 |
52 | org.springframework.boot
53 | spring-boot-starter-security
54 |
55 |
56 |
57 | org.springframework.security.oauth
58 | spring-security-oauth2
59 | 2.3.3.RELEASE
60 |
61 |
62 |
63 |
64 | mysql
65 | mysql-connector-java
66 | 5.1.47
67 | runtime
68 |
69 |
70 | org.springframework.boot
71 | spring-boot-starter-data-jpa
72 |
73 |
74 |
75 |
76 | com.alibaba
77 | fastjson
78 | 1.2.47
79 |
80 |
81 |
82 |
83 |
84 |
85 | org.springframework.boot
86 | spring-boot-maven-plugin
87 |
88 |
89 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/src/main/java/com/unionman/springbootsecurityauth2/SpringbootSecurityAuth2Application.java:
--------------------------------------------------------------------------------
1 | package com.unionman.springbootsecurityauth2;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class SpringbootSecurityAuth2Application {
8 |
9 | public static void main(String[] args) {
10 | SpringApplication.run(SpringbootSecurityAuth2Application.class, args);
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/com/unionman/springbootsecurityauth2/config/HttpMessageConverterConfig.java:
--------------------------------------------------------------------------------
1 | package com.unionman.springbootsecurityauth2.config;
2 |
3 | import com.alibaba.fastjson.JSON;
4 | import com.alibaba.fastjson.serializer.SerializerFeature;
5 | import com.alibaba.fastjson.support.config.FastJsonConfig;
6 | import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
7 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
8 | import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
9 | import org.springframework.context.annotation.Bean;
10 | import org.springframework.context.annotation.Configuration;
11 | import org.springframework.http.MediaType;
12 | import org.springframework.http.converter.HttpMessageConverter;
13 | import org.springframework.http.converter.StringHttpMessageConverter;
14 |
15 | import java.nio.charset.Charset;
16 | import java.util.ArrayList;
17 | import java.util.List;
18 |
19 | /**
20 | * @description: 自定义消息转换器,该配置是将json与form-data之间数据相互转换
21 | */
22 | @Configuration
23 | @ConditionalOnClass(JSON.class)
24 | public class HttpMessageConverterConfig {
25 |
26 | /**
27 | * @return StringHttpMessageConverter
28 | * @descrption: http消息转换器。
29 | * @author Rong.Jia
30 | * @date 2019/01/07 25:16:44
31 | */
32 | @Bean
33 | public StringHttpMessageConverter stringHttpMessageConverter() {
34 | StringHttpMessageConverter converter = new StringHttpMessageConverter(Charset.forName("UTF-8"));
35 | return converter;
36 | }
37 |
38 | @Bean
39 | public HttpMessageConverters fastJsonHttpMessageConverters() {
40 |
41 | // 1.定义一个converters转换消息的对象
42 | FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
43 |
44 | // 2.添加fastjson的配置信息,比如: 是否需要格式化返回的json数据
45 | FastJsonConfig fastJsonConfig = new FastJsonConfig();
46 |
47 | fastJsonConfig.setSerializerFeatures(SerializerFeature.QuoteFieldNames,
48 | SerializerFeature.WriteEnumUsingToString,
49 | //SerializerFeature.WriteMapNullValue,
50 | SerializerFeature.WriteDateUseDateFormat,
51 | SerializerFeature.DisableCircularReferenceDetect
52 | );
53 | // 3.在converter中添加配置信息
54 | fastConverter.setFastJsonConfig(fastJsonConfig);
55 | List fastMediaTypes = new ArrayList<>();
56 | fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
57 | fastConverter.setSupportedMediaTypes(fastMediaTypes);
58 |
59 | // 4.将converter赋值给HttpMessageConverter
60 | HttpMessageConverter> converter = fastConverter;
61 |
62 | // 5.返回HttpMessageConverters对象
63 | return new HttpMessageConverters(converter);
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/main/java/com/unionman/springbootsecurityauth2/config/OAuth2Config.java:
--------------------------------------------------------------------------------
1 | package com.unionman.springbootsecurityauth2.config;
2 |
3 | import com.unionman.springbootsecurityauth2.handler.CustomAuthExceptionHandler;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.context.annotation.Bean;
6 | import org.springframework.context.annotation.Configuration;
7 | import org.springframework.data.redis.connection.RedisConnectionFactory;
8 | import org.springframework.http.HttpMethod;
9 | import org.springframework.security.authentication.AuthenticationManager;
10 | import org.springframework.security.config.annotation.web.builders.HttpSecurity;
11 | import org.springframework.security.config.http.SessionCreationPolicy;
12 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
13 | import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
14 | import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
15 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
16 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
17 | import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
18 | import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
19 | import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
20 | import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
21 | import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
22 | import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
23 |
24 | import java.util.concurrent.TimeUnit;
25 |
26 |
27 |
28 | /**
29 | * @author Zhifeng.Zeng
30 | * @description OAuth2服务器配置
31 | */
32 | @Configuration
33 | public class OAuth2Config {
34 |
35 | public static final String ROLE_ADMIN = "ADMIN";
36 | //访问客户端密钥
37 | public static final String CLIENT_SECRET = "123456";
38 | //访问客户端ID
39 | public static final String CLIENT_ID ="client_1";
40 | //鉴权模式
41 | public static final String GRANT_TYPE[] = {"password","refresh_token"};
42 |
43 | /**
44 | * @description 资源服务器
45 | */
46 | @Configuration
47 | @EnableResourceServer
48 | protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
49 |
50 | @Autowired
51 | private CustomAuthExceptionHandler customAuthExceptionHandler;
52 |
53 | @Override
54 | public void configure(ResourceServerSecurityConfigurer resources) {
55 | resources.stateless(false)
56 | .accessDeniedHandler(customAuthExceptionHandler)
57 | .authenticationEntryPoint(customAuthExceptionHandler);
58 | }
59 |
60 | @Override
61 | public void configure(HttpSecurity http) throws Exception {
62 | http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
63 | .and()
64 | //请求权限配置
65 | .authorizeRequests()
66 | //下边的路径放行,不需要经过认证
67 | .antMatchers("/oauth/*", "/auth/user/login").permitAll()
68 | //OPTIONS请求不需要鉴权
69 | .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
70 | //用户的增删改接口只允许管理员访问
71 | .antMatchers(HttpMethod.POST, "/auth/user").hasAnyAuthority(ROLE_ADMIN)
72 | .antMatchers(HttpMethod.PUT, "/auth/user").hasAnyAuthority(ROLE_ADMIN)
73 | .antMatchers(HttpMethod.DELETE, "/auth/user").hasAnyAuthority(ROLE_ADMIN)
74 | //获取角色 权限列表接口只允许系统管理员及高级用户访问
75 | .antMatchers(HttpMethod.GET, "/auth/role").hasAnyAuthority(ROLE_ADMIN)
76 | //其余接口没有角色限制,但需要经过认证,只要携带token就可以放行
77 | .anyRequest()
78 | .authenticated();
79 |
80 | }
81 | }
82 |
83 | /**
84 | * @description 认证授权服务器
85 | */
86 | @Configuration
87 | @EnableAuthorizationServer
88 | protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
89 |
90 | @Autowired
91 | private AuthenticationManager authenticationManager;
92 |
93 | @Autowired
94 | private RedisConnectionFactory connectionFactory;
95 |
96 | @Override
97 | public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
98 | String finalSecret = "{bcrypt}" + new BCryptPasswordEncoder().encode(CLIENT_SECRET);
99 | //配置客户端,使用密码模式验证鉴权
100 | clients.inMemory()
101 | .withClient(CLIENT_ID)
102 | //密码模式及refresh_token模式
103 | .authorizedGrantTypes(GRANT_TYPE[0], GRANT_TYPE[1])
104 | .scopes("all")
105 | .secret(finalSecret);
106 | }
107 |
108 | @Bean
109 | public RedisTokenStore redisTokenStore() {
110 | return new RedisTokenStore(connectionFactory);
111 | }
112 |
113 | /**
114 | * @description token及用户信息存储到redis,当然你也可以存储在当前的服务内存,不推荐
115 | * @param endpoints
116 | */
117 | @Override
118 | public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
119 | //token信息存到服务内存
120 | /*endpoints.tokenStore(new InMemoryTokenStore())
121 | .authenticationManager(authenticationManager);*/
122 |
123 | //token信息存到redis
124 | endpoints.tokenStore(redisTokenStore()).authenticationManager(authenticationManager);
125 | //配置TokenService参数
126 | DefaultTokenServices tokenService = new DefaultTokenServices();
127 | tokenService.setTokenStore(endpoints.getTokenStore());
128 | tokenService.setSupportRefreshToken(true);
129 | tokenService.setClientDetailsService(endpoints.getClientDetailsService());
130 | tokenService.setTokenEnhancer(endpoints.getTokenEnhancer());
131 | //1小时
132 | tokenService.setAccessTokenValiditySeconds((int) TimeUnit.HOURS.toSeconds(1));
133 | //1小时
134 | tokenService.setRefreshTokenValiditySeconds((int) TimeUnit.HOURS.toSeconds(1));
135 | tokenService.setReuseRefreshToken(false);
136 | endpoints.tokenServices(tokenService);
137 | }
138 |
139 | @Override
140 | public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
141 | //允许表单认证
142 | oauthServer.allowFormAuthenticationForClients().tokenKeyAccess("isAuthenticated()")
143 | .checkTokenAccess("permitAll()");
144 | }
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/src/main/java/com/unionman/springbootsecurityauth2/config/RedisConfig.java:
--------------------------------------------------------------------------------
1 | package com.unionman.springbootsecurityauth2.config;
2 |
3 | import com.fasterxml.jackson.annotation.JsonAutoDetect;
4 | import com.fasterxml.jackson.annotation.PropertyAccessor;
5 | import com.fasterxml.jackson.databind.ObjectMapper;
6 | import org.springframework.cache.annotation.CachingConfigurerSupport;
7 | import org.springframework.context.annotation.Bean;
8 | import org.springframework.context.annotation.Configuration;
9 | import org.springframework.data.redis.connection.RedisConnectionFactory;
10 | import org.springframework.data.redis.core.RedisTemplate;
11 | import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
12 | import org.springframework.data.redis.serializer.RedisSerializer;
13 | import org.springframework.data.redis.serializer.StringRedisSerializer;
14 |
15 |
16 | /**
17 | * @description redis 配置
18 | */
19 | @Configuration
20 | public class RedisConfig extends CachingConfigurerSupport {
21 |
22 | /**
23 | * @description redis模板,存储关键字是字符串,值jackson2JsonRedisSerializer是序列化后的值
24 | */
25 | @Bean
26 | public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) {
27 | RedisTemplate redisTemplate = new RedisTemplate<>();
28 | redisTemplate.setConnectionFactory(connectionFactory);
29 | //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
30 | Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
31 | ObjectMapper objectMapper = new ObjectMapper();
32 | objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
33 | objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
34 | jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
35 | //使用StringRedisSerializer来序列化和反序列化redis的key值
36 | RedisSerializer redisSerializer = new StringRedisSerializer();
37 | redisTemplate.setKeySerializer(redisSerializer);
38 | redisTemplate.setHashKeySerializer(redisSerializer);
39 | redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
40 | redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
41 | redisTemplate.afterPropertiesSet();
42 | return redisTemplate;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/com/unionman/springbootsecurityauth2/config/SecurityConfig.java:
--------------------------------------------------------------------------------
1 | package com.unionman.springbootsecurityauth2.config;
2 |
3 | import com.unionman.springbootsecurityauth2.domain.CustomUserDetail;
4 | import com.unionman.springbootsecurityauth2.entity.User;
5 | import com.unionman.springbootsecurityauth2.repository.UserRepository;
6 | import lombok.extern.slf4j.Slf4j;
7 | import org.springframework.beans.factory.annotation.Autowired;
8 | import org.springframework.context.annotation.Bean;
9 | import org.springframework.context.annotation.Configuration;
10 | import org.springframework.security.authentication.AuthenticationManager;
11 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
12 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
13 | import org.springframework.security.core.GrantedAuthority;
14 | import org.springframework.security.core.authority.AuthorityUtils;
15 | import org.springframework.security.core.userdetails.UserDetails;
16 | import org.springframework.security.core.userdetails.UserDetailsService;
17 | import org.springframework.security.core.userdetails.UsernameNotFoundException;
18 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
19 | import org.springframework.security.crypto.factory.PasswordEncoderFactories;
20 | import org.springframework.security.crypto.password.PasswordEncoder;
21 | import org.springframework.web.client.RestTemplate;
22 |
23 | import java.util.List;
24 |
25 | /**
26 | * @description Security核心配置
27 | * @author Zhifeng.Zeng
28 | */
29 | @Configuration
30 | @EnableWebSecurity
31 | @Slf4j
32 | public class SecurityConfig extends WebSecurityConfigurerAdapter {
33 |
34 |
35 | @Autowired
36 | private UserRepository userRepository;
37 |
38 | @Bean
39 | @Override
40 | public AuthenticationManager authenticationManagerBean() throws Exception {
41 | return super.authenticationManagerBean();
42 | }
43 |
44 | @Bean
45 | public RestTemplate restTemplate(){
46 | return new RestTemplate();
47 | }
48 |
49 | @Bean
50 | @Override
51 | protected UserDetailsService userDetailsService() {
52 | BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
53 | return new UserDetailsService(){
54 | @Override
55 | public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
56 | log.info("username:{}",username);
57 | User user = userRepository.findUserByAccount(username);
58 | if(user != null){
59 | CustomUserDetail customUserDetail = new CustomUserDetail();
60 | customUserDetail.setUsername(user.getAccount());
61 | customUserDetail.setPassword("{bcrypt}"+bCryptPasswordEncoder.encode(user.getPassword()));
62 | List list = AuthorityUtils.createAuthorityList(user.getRole().getRole());
63 | customUserDetail.setAuthorities(list);
64 | return customUserDetail;
65 | }else {//返回空
66 | return null;
67 | }
68 |
69 | }
70 | };
71 | }
72 |
73 | @Bean
74 | PasswordEncoder passwordEncoder() {
75 | return PasswordEncoderFactories.createDelegatingPasswordEncoder();
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/main/java/com/unionman/springbootsecurityauth2/config/ServerConfig.java:
--------------------------------------------------------------------------------
1 | package com.unionman.springbootsecurityauth2.config;
2 |
3 | import org.springframework.beans.factory.annotation.Value;
4 | import org.springframework.boot.web.context.WebServerInitializedEvent;
5 | import org.springframework.context.ApplicationListener;
6 | import org.springframework.stereotype.Component;
7 |
8 | import java.net.InetAddress;
9 | import java.net.UnknownHostException;
10 |
11 | /**
12 | * @author Rong.Jia
13 | * @description: server 配置
14 | * @date 2019/02/19 15:24:22
15 | */
16 | @Component
17 | public class ServerConfig implements ApplicationListener {
18 |
19 | @Value("${server.host}")
20 | private String ip;
21 |
22 | private int serverPort;
23 |
24 | public String getUrl() {
25 | InetAddress address = null;
26 | try {
27 | address = InetAddress.getLocalHost();
28 | } catch (UnknownHostException e) {
29 | e.printStackTrace();
30 | }
31 | return "http://" + ip + ":" + this.serverPort;
32 | }
33 |
34 | public int getPort() {
35 | return this.serverPort;
36 | }
37 |
38 | @Override
39 | public void onApplicationEvent(WebServerInitializedEvent event) {
40 | this.serverPort = event.getWebServer().getPort();
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/com/unionman/springbootsecurityauth2/controller/AuthController.java:
--------------------------------------------------------------------------------
1 | package com.unionman.springbootsecurityauth2.controller;
2 |
3 | import com.unionman.springbootsecurityauth2.dto.LoginUserDTO;
4 | import com.unionman.springbootsecurityauth2.dto.UserDTO;
5 | import com.unionman.springbootsecurityauth2.service.RoleService;
6 | import com.unionman.springbootsecurityauth2.service.UserService;
7 | import com.unionman.springbootsecurityauth2.utils.AssertUtils;
8 | import com.unionman.springbootsecurityauth2.vo.ResponseVO;
9 | import lombok.extern.slf4j.Slf4j;
10 | import org.springframework.beans.factory.annotation.Autowired;
11 | import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
12 | import org.springframework.validation.annotation.Validated;
13 | import org.springframework.web.bind.annotation.*;
14 |
15 | import javax.validation.Valid;
16 |
17 | /**
18 | * @description 用户权限管理
19 | * @author Zhifeng.Zeng
20 | * @date 2019/4/19 13:58
21 | */
22 | @Slf4j
23 | @Validated
24 | @RestController
25 | @RequestMapping("/auth/")
26 | public class AuthController {
27 |
28 | @Autowired
29 | private UserService userService;
30 |
31 | @Autowired
32 | private RoleService roleService;
33 |
34 | @Autowired
35 | private RedisTokenStore redisTokenStore;
36 |
37 | /**
38 | * @description 添加用户
39 | * @param userDTO
40 | * @return
41 | */
42 | @PostMapping("user")
43 | public ResponseVO add(@Valid @RequestBody UserDTO userDTO) throws Exception {
44 | userService.addUser(userDTO);
45 | return ResponseVO.success();
46 | }
47 |
48 | /**
49 | * @description 删除用户
50 | * @param id
51 | * @return
52 | */
53 | @DeleteMapping("user/{id}")
54 | public ResponseVO deleteUser(@PathVariable("id")Integer id) throws Exception {
55 | userService.deleteUser(id);
56 | return ResponseVO.success();
57 | }
58 |
59 | /**
60 | * @descripiton 修改用户
61 | * @param userDTO
62 | * @return
63 | */
64 | @PutMapping("user")
65 | public ResponseVO updateUser(@Valid @RequestBody UserDTO userDTO){
66 | userService.updateUser(userDTO);
67 | return ResponseVO.success();
68 | }
69 |
70 | /**
71 | * @description 获取用户列表
72 | * @return
73 | */
74 | @GetMapping("user")
75 | public ResponseVO findAllUser(){
76 | return userService.findAllUserVO();
77 | }
78 |
79 | /**
80 | * @description 用户登录
81 | * @param loginUserDTO
82 | * @return
83 | */
84 | @PostMapping("user/login")
85 | public ResponseVO login(LoginUserDTO loginUserDTO){
86 | return userService.login(loginUserDTO);
87 | }
88 |
89 |
90 | /**
91 | * @description 用户注销
92 | * @param authorization
93 | * @return
94 | */
95 | @GetMapping("user/logout")
96 | public ResponseVO logout(@RequestHeader("Authorization") String authorization){
97 | redisTokenStore.removeAccessToken(AssertUtils.extracteToken(authorization));
98 | return ResponseVO.success();
99 | }
100 |
101 | /**
102 | * @description 获取所有角色列表
103 | * @return
104 | */
105 | @GetMapping("role")
106 | public ResponseVO findAllRole(){
107 | return roleService.findAllRoleVO();
108 | }
109 |
110 |
111 | }
112 |
--------------------------------------------------------------------------------
/src/main/java/com/unionman/springbootsecurityauth2/domain/Base.java:
--------------------------------------------------------------------------------
1 | package com.unionman.springbootsecurityauth2.domain;
2 |
3 | import lombok.Data;
4 |
5 | import javax.persistence.GeneratedValue;
6 | import javax.persistence.GenerationType;
7 | import javax.persistence.Id;
8 | import javax.persistence.MappedSuperclass;
9 | import javax.validation.constraints.NotNull;
10 | import java.io.Serializable;
11 |
12 | /**
13 | * @description:
14 | * @date 2019/02/19 18:01:22
15 | * @author Rong.Jia
16 | */
17 | @Data
18 | @MappedSuperclass
19 | public class Base implements Serializable {
20 |
21 | private static final long serialVersionUID = -7519418012137093264L;
22 |
23 | @Id
24 | @GeneratedValue(strategy = GenerationType.IDENTITY)
25 | protected Integer id;
26 |
27 | /**
28 | * 添加时间
29 | */
30 | protected Long createdTime;
31 |
32 |
33 | /**
34 | * 描述
35 | */
36 | protected String description;
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/com/unionman/springbootsecurityauth2/domain/CustomUserDetail.java:
--------------------------------------------------------------------------------
1 | package com.unionman.springbootsecurityauth2.domain;
2 |
3 | import lombok.Setter;
4 | import org.springframework.security.core.GrantedAuthority;
5 | import org.springframework.security.core.userdetails.UserDetails;
6 |
7 | import java.io.Serializable;
8 | import java.util.Collection;
9 |
10 | /**
11 | * @author Zhifeng.Zeng
12 | * @description 自定义userDetail 关联security oauth2
13 | * @date 2019/3/4
14 | */
15 | @Setter
16 | public class CustomUserDetail implements UserDetails, Serializable {
17 | private static final long serialVersionUID = -8478114427891717226L;
18 |
19 | /**
20 | * 用户名
21 | */
22 | private String username;
23 | /**
24 | * 密码
25 | */
26 | private String password;
27 | /**
28 | * 账户生效
29 | */
30 | private boolean accountNonExpired = true;
31 | /**
32 | * 账户锁定
33 | */
34 | private boolean accountNonLocked = true;
35 | /**
36 | * 凭证生效
37 | */
38 | private boolean credentialsNonExpired = true;
39 | /**
40 | * 激活状态
41 | */
42 | private boolean enabled = true;
43 | /**
44 | * 权限列表
45 | */
46 | private Collection authorities;
47 |
48 | @Override
49 | public Collection extends GrantedAuthority> getAuthorities() {
50 | return authorities;
51 | }
52 |
53 | @Override
54 | public String getPassword() {
55 | return password;
56 | }
57 |
58 | @Override
59 | public String getUsername() {
60 | return username;
61 | }
62 |
63 | @Override
64 | public boolean isAccountNonExpired() {
65 | return accountNonExpired;
66 | }
67 |
68 | @Override
69 | public boolean isAccountNonLocked() {
70 | return accountNonLocked;
71 | }
72 |
73 | @Override
74 | public boolean isCredentialsNonExpired() {
75 | return credentialsNonExpired;
76 | }
77 |
78 | @Override
79 | public boolean isEnabled() {
80 | return enabled;
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/src/main/java/com/unionman/springbootsecurityauth2/domain/Token.java:
--------------------------------------------------------------------------------
1 | package com.unionman.springbootsecurityauth2.domain;
2 |
3 | import com.unionman.springbootsecurityauth2.domain.bean.RefreshTokenBean;
4 |
5 | import java.util.List;
6 |
7 | /**
8 | * @author Zhifeng.Zeng
9 | * @description oauth2客户端token参数
10 | * @date 2019/3/8
11 | */
12 | public class Token {
13 |
14 | /**
15 | * 过期时间
16 | */
17 | private String expiration;
18 | /**
19 | * 是否过期
20 | */
21 | private boolean expired;
22 | /**
23 | * 过期时限
24 | */
25 | private int expiresIn;
26 | /**
27 | * refreshToken对象
28 | */
29 | private RefreshTokenBean refreshToken;
30 |
31 | /**
32 | * token类型
33 | */
34 | private String tokenType;
35 |
36 | /**
37 | * access_token值
38 | */
39 | private String value;
40 |
41 | /**
42 | * 使用范围
43 | */
44 | private List scope;
45 |
46 |
47 | public String getExpiration() {
48 | return expiration;
49 | }
50 |
51 | public void setExpiration(String expiration) {
52 | this.expiration = expiration;
53 | }
54 |
55 | public boolean isExpired() {
56 | return expired;
57 | }
58 |
59 | public void setExpired(boolean expired) {
60 | this.expired = expired;
61 | }
62 |
63 | public int getExpiresIn() {
64 | return expiresIn;
65 | }
66 |
67 | public void setExpiresIn(int expiresIn) {
68 | this.expiresIn = expiresIn;
69 | }
70 |
71 | public RefreshTokenBean getRefreshToken() {
72 | return refreshToken;
73 | }
74 |
75 | public void setRefreshToken(RefreshTokenBean refreshToken) {
76 | this.refreshToken = refreshToken;
77 | }
78 |
79 | public String getTokenType() {
80 | return tokenType;
81 | }
82 |
83 | public void setTokenType(String tokenType) {
84 | this.tokenType = tokenType;
85 | }
86 |
87 | public String getValue() {
88 | return value;
89 | }
90 |
91 | public void setValue(String value) {
92 | this.value = value;
93 | }
94 |
95 | public List getScope() {
96 | return scope;
97 | }
98 |
99 | public void setScope(List scope) {
100 | this.scope = scope;
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/src/main/java/com/unionman/springbootsecurityauth2/domain/bean/RefreshTokenBean.java:
--------------------------------------------------------------------------------
1 | package com.unionman.springbootsecurityauth2.domain.bean;
2 |
3 | import lombok.Data;
4 |
5 | @Data
6 | public class RefreshTokenBean {
7 |
8 | /**
9 | * 过期时间
10 | */
11 | private String expiration;
12 | /**
13 | * token值
14 | */
15 | private String value;
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/com/unionman/springbootsecurityauth2/dto/LoginUserDTO.java:
--------------------------------------------------------------------------------
1 | package com.unionman.springbootsecurityauth2.dto;
2 |
3 | import lombok.Data;
4 |
5 |
6 | /**
7 | * @description 登录用户传输参数
8 | * @author Zhifeng.Zeng
9 | * @date 2019/4/19 14:26
10 | */
11 | @Data
12 | public class LoginUserDTO {
13 |
14 | /**
15 | * 用户名
16 | */
17 | private String account;
18 |
19 | /**
20 | * 用户密码
21 | */
22 | private String password;
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/com/unionman/springbootsecurityauth2/dto/ModifyUserDTO.java:
--------------------------------------------------------------------------------
1 | package com.unionman.springbootsecurityauth2.dto;
2 |
3 | import lombok.Data;
4 |
5 | /**
6 | * @description 用户修改密码传输参数
7 | * @author Zhifeng.Zeng
8 | * @date 2019/4/19 14:26
9 | */
10 | @Data
11 | public class ModifyUserDTO {
12 |
13 | /**
14 | * 原密码
15 | */
16 | String oldPassword;
17 |
18 | /**
19 | * 新密码
20 | */
21 | String newPassword;
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/com/unionman/springbootsecurityauth2/dto/UserDTO.java:
--------------------------------------------------------------------------------
1 | package com.unionman.springbootsecurityauth2.dto;
2 |
3 | import com.unionman.springbootsecurityauth2.domain.Base;
4 | import lombok.Data;
5 |
6 | import javax.validation.constraints.NotNull;
7 |
8 | /**
9 | * @description 添加、修改用户传输参数
10 | * @author Zhifeng.Zeng
11 | * @date 2019/4/19
12 | */
13 | @Data
14 | public class UserDTO extends Base {
15 |
16 | /**
17 | * 用户名
18 | */
19 | private String account;
20 | /**
21 | * 用户姓名
22 | */
23 | private String name;
24 | /**
25 | * 用户密码
26 | */
27 | private String password;
28 | /**
29 | * 用户角色id
30 | */
31 | private Integer roleId;
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/com/unionman/springbootsecurityauth2/entity/Role.java:
--------------------------------------------------------------------------------
1 | package com.unionman.springbootsecurityauth2.entity;
2 |
3 | import com.fasterxml.jackson.annotation.JsonBackReference;
4 | import com.unionman.springbootsecurityauth2.domain.Base;
5 | import lombok.Getter;
6 | import lombok.Setter;
7 |
8 | import javax.persistence.*;
9 | import java.io.Serializable;
10 | import java.util.Set;
11 |
12 | @Getter
13 | @Setter
14 | @Entity
15 | @Table(name = "um_t_role")
16 | public class Role extends Base implements Serializable {
17 |
18 | private static final long serialVersionUID = -8478114427891717226L;
19 |
20 | /**
21 | * 角色名
22 | */
23 | private String name;
24 |
25 | /**
26 | * 角色
27 | */
28 | private String role;
29 |
30 | /**
31 | * 角色 -- 用户: 1对多
32 | */
33 | @JsonBackReference
34 | @OneToMany(fetch = FetchType.EAGER)
35 | @JoinTable(name = "um_t_role_user", joinColumns = {@JoinColumn(name = "roleId")}, inverseJoinColumns = {@JoinColumn(name = "userId")})
36 | private Set users;
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/com/unionman/springbootsecurityauth2/entity/User.java:
--------------------------------------------------------------------------------
1 | package com.unionman.springbootsecurityauth2.entity;
2 |
3 | import com.fasterxml.jackson.annotation.JsonBackReference;
4 | import com.unionman.springbootsecurityauth2.domain.Base;
5 | import lombok.Getter;
6 | import lombok.Setter;
7 |
8 | import javax.persistence.*;
9 | import java.io.Serializable;
10 |
11 | @Getter
12 | @Setter
13 | @Entity
14 | @Table(name = "um_t_user")
15 | public class User extends Base implements Serializable {
16 | private static final long serialVersionUID = -8478114427891717226L;
17 |
18 | /**
19 | * 用户账号
20 | */
21 | private String account;
22 |
23 | /**
24 | * 用户名
25 | */
26 | private String name;
27 |
28 | /**
29 | * 用户密码
30 | */
31 | private String password;
32 |
33 | /**
34 | * 用户 --角色 多对一
35 | */
36 | @JsonBackReference
37 | @ManyToOne(fetch = FetchType.EAGER)
38 | @JoinTable(name = "um_t_role_user", joinColumns = {@JoinColumn(name = "userId")}, inverseJoinColumns = {@JoinColumn(name = "roleId")})
39 | private Role role;
40 |
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/com/unionman/springbootsecurityauth2/enums/ResponseEnum.java:
--------------------------------------------------------------------------------
1 | package com.unionman.springbootsecurityauth2.enums;
2 |
3 | import lombok.ToString;
4 |
5 | /**
6 | * @description: 数据信息状态枚举类
7 | * @author Rong.Jia
8 | * @date 2019/02/19 15:54:22
9 | */
10 | @ToString
11 | public enum ResponseEnum {
12 |
13 |
14 |
15 | /**
16 | * 0 表示返回成功
17 | */
18 | SUCCESS(0,"成功"),
19 |
20 | /**
21 | * 表示接口调用方异常提示
22 | */
23 | ACCESS_TOKEN_INVALID(1001,"access_token无效"),
24 | REFRESH_TOKEN_INVALID(1002,"refresh_token无效"),
25 | INSUFFICIENT_PERMISSIONS(1003,"该用户权限不足以访问该资源接口"),
26 | UNAUTHORIZED(1004,"访问此资源需要完全的身份验证"),
27 |
28 |
29 | /**
30 | * 5000 表示用户提示信息
31 | */
32 | INCORRECT_PARAMS(5000, "参数不正确"),
33 | ;
34 | private Integer code;
35 | private String message;
36 |
37 | ResponseEnum(Integer code, String message) {
38 | this.code = code;
39 | this.message = message;
40 | }
41 |
42 | public Integer getCode() {
43 | return code;
44 | }
45 |
46 | public String getMessage() {
47 | return message;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/com/unionman/springbootsecurityauth2/enums/UrlEnum.java:
--------------------------------------------------------------------------------
1 | package com.unionman.springbootsecurityauth2.enums;
2 |
3 | /**
4 | * @description: url 枚举类
5 | * @author: Rong.Jia
6 | * @date: 2019/02/28 09:22:22
7 | */
8 | public enum UrlEnum {
9 |
10 | //oauth2登录
11 | LOGIN_URL("/oauth/token"),
12 |
13 | ;
14 |
15 | private String url;
16 |
17 | UrlEnum(String url) {
18 | this.url = url;
19 |
20 | }
21 |
22 |
23 | public String getUrl() {
24 | return url;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/com/unionman/springbootsecurityauth2/handler/CustomAuthExceptionHandler.java:
--------------------------------------------------------------------------------
1 | package com.unionman.springbootsecurityauth2.handler;
2 |
3 | import com.alibaba.fastjson.JSON;
4 | import com.unionman.springbootsecurityauth2.enums.ResponseEnum;
5 | import com.unionman.springbootsecurityauth2.vo.ResponseVO;
6 | import lombok.extern.slf4j.Slf4j;
7 | import org.springframework.security.access.AccessDeniedException;
8 | import org.springframework.security.core.AuthenticationException;
9 | import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
10 | import org.springframework.security.web.AuthenticationEntryPoint;
11 | import org.springframework.security.web.access.AccessDeniedHandler;
12 | import org.springframework.stereotype.Component;
13 |
14 | import javax.servlet.ServletException;
15 | import javax.servlet.http.HttpServletRequest;
16 | import javax.servlet.http.HttpServletResponse;
17 | import java.io.IOException;
18 |
19 | /**
20 | * @author Zhifeng.Zeng
21 | * @description 自定义未授权 token无效 权限不足返回信息处理类
22 | * @date 2019/3/4 15:49
23 | */
24 | @Component
25 | @Slf4j
26 | public class CustomAuthExceptionHandler implements AuthenticationEntryPoint, AccessDeniedHandler {
27 | @Override
28 | public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
29 |
30 | Throwable cause = authException.getCause();
31 | response.setContentType("application/json;charset=UTF-8");
32 | response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
33 | // CORS "pre-flight" request
34 | response.addHeader("Access-Control-Allow-Origin", "*");
35 | response.addHeader("Cache-Control","no-cache");
36 | response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
37 | response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
38 | response.addHeader("Access-Control-Max-Age", "1800");
39 | if (cause instanceof InvalidTokenException) {
40 | log.error("InvalidTokenException : {}",cause.getMessage());
41 | //Token无效
42 | response.getWriter().write(JSON.toJSONString(ResponseVO.error(ResponseEnum.ACCESS_TOKEN_INVALID)));
43 | } else {
44 | log.error("AuthenticationException : NoAuthentication");
45 | //资源未授权
46 | response.getWriter().write(JSON.toJSONString(ResponseVO.error(ResponseEnum.UNAUTHORIZED)));
47 | }
48 |
49 | }
50 |
51 | @Override
52 | public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
53 | response.setContentType("application/json;charset=UTF-8");
54 | response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
55 | response.addHeader("Access-Control-Allow-Origin", "*");
56 | response.addHeader("Cache-Control","no-cache");
57 | response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
58 | response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
59 | response.addHeader("Access-Control-Max-Age", "1800");
60 | //访问资源的用户权限不足
61 | log.error("AccessDeniedException : {}",accessDeniedException.getMessage());
62 | response.getWriter().write(JSON.toJSONString(ResponseVO.error(ResponseEnum.INSUFFICIENT_PERMISSIONS)));
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/main/java/com/unionman/springbootsecurityauth2/repository/RoleRepository.java:
--------------------------------------------------------------------------------
1 | package com.unionman.springbootsecurityauth2.repository;
2 |
3 |
4 | import com.unionman.springbootsecurityauth2.entity.Role;
5 | import com.unionman.springbootsecurityauth2.repository.base.BaseRepository;
6 |
7 | public interface RoleRepository extends BaseRepository {
8 | }
9 |
--------------------------------------------------------------------------------
/src/main/java/com/unionman/springbootsecurityauth2/repository/UserRepository.java:
--------------------------------------------------------------------------------
1 | package com.unionman.springbootsecurityauth2.repository;
2 |
3 | import com.unionman.springbootsecurityauth2.entity.User;
4 | import com.unionman.springbootsecurityauth2.repository.base.BaseRepository;
5 |
6 | public interface UserRepository extends BaseRepository {
7 |
8 | User findUserByAccount(String account);
9 | }
10 |
--------------------------------------------------------------------------------
/src/main/java/com/unionman/springbootsecurityauth2/repository/base/BaseRepository.java:
--------------------------------------------------------------------------------
1 | package com.unionman.springbootsecurityauth2.repository.base;
2 |
3 | import org.springframework.data.jpa.repository.JpaRepository;
4 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
5 | import org.springframework.data.repository.NoRepositoryBean;
6 |
7 | import java.util.List;
8 | import java.util.Optional;
9 |
10 | /**
11 | * @description: 抽取持久层通用方法
12 | * @param
13 | * @author: Rong.Jia
14 | * @date: 2019/01/14 17:00
15 | */
16 | @NoRepositoryBean
17 | public interface BaseRepository extends JpaRepository, JpaSpecificationExecutor {
18 |
19 | /**
20 | * @param id 信息唯一标识
21 | * @return T 获取的信息
22 | * @description: 根据id 获取信息
23 | * @author: Rong.Jia
24 | * @date: 2019/01/14 17:00
25 | */
26 | @Override
27 | Optional findById(Integer id);
28 |
29 | /**
30 | * @return 将获取的信息封装到List中 返回
31 | * @description: 获取所有的信息
32 | * @author: Rong.Jia
33 | * @date: 2019/01/14 17:00
34 | */
35 | @Override
36 | List findAll();
37 |
38 | /**
39 | * @param entity 实体类信息
40 | * @description: 删除指定的信息
41 | * @author: Rong.Jia
42 | * @date: 2019/01/14 17:00
43 | */
44 | @Override
45 | void delete(T entity);
46 |
47 | /**
48 | * @param id 唯一标识
49 | * @description: 根据id 删除信息
50 | * @author: Rong.Jia
51 | * @date: 2019/01/14 17:00
52 | */
53 | @Override
54 | void deleteById(Integer id);
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/com/unionman/springbootsecurityauth2/service/RoleService.java:
--------------------------------------------------------------------------------
1 | package com.unionman.springbootsecurityauth2.service;
2 |
3 |
4 | import com.unionman.springbootsecurityauth2.entity.Role;
5 | import com.unionman.springbootsecurityauth2.vo.ResponseVO;
6 |
7 | /**
8 | * @description 角色管理接口
9 | * @author Zhifeng.Zeng
10 | * @date 2019/2/21 11:05
11 | */
12 | public interface RoleService {
13 |
14 | /**
15 | * @description 获取角色列表
16 | * @return
17 | */
18 | ResponseVO findAllRoleVO();
19 |
20 | /**
21 | * @description 根据角色id获取角色
22 | */
23 | Role findById(Integer id);
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/com/unionman/springbootsecurityauth2/service/UserService.java:
--------------------------------------------------------------------------------
1 | package com.unionman.springbootsecurityauth2.service;
2 |
3 |
4 | import com.unionman.springbootsecurityauth2.dto.LoginUserDTO;
5 | import com.unionman.springbootsecurityauth2.dto.UserDTO;
6 | import com.unionman.springbootsecurityauth2.vo.ResponseVO;
7 | import com.unionman.springbootsecurityauth2.vo.UserVO;
8 |
9 | import java.util.List;
10 |
11 | /**
12 | * @description 用户业务接口
13 | * @author Zhifeng.Zeng
14 | * @date 2019/2/21 14:06
15 | */
16 | public interface UserService {
17 |
18 | /**
19 | * @description 添加用户
20 | */
21 | void addUser(UserDTO userDTO) throws Exception;
22 |
23 | /**
24 | * 删除用户
25 | * @param id
26 | */
27 | void deleteUser(Integer id) throws Exception;
28 |
29 | /**
30 | * @description 修改用户信息
31 | * @param userDTO
32 | */
33 | void updateUser(UserDTO userDTO);
34 |
35 | /**
36 | * @description 获取所有用户列表VO
37 | * @return
38 | */
39 | ResponseVO> findAllUserVO();
40 |
41 | /**
42 | * @description 用户登录
43 | * @return
44 | */
45 | ResponseVO login(LoginUserDTO loginUserDTO);
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/com/unionman/springbootsecurityauth2/service/impl/RoleServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.unionman.springbootsecurityauth2.service.impl;
2 |
3 | import com.unionman.springbootsecurityauth2.entity.Role;
4 | import com.unionman.springbootsecurityauth2.repository.RoleRepository;
5 | import com.unionman.springbootsecurityauth2.service.RoleService;
6 | import com.unionman.springbootsecurityauth2.vo.ResponseVO;
7 | import com.unionman.springbootsecurityauth2.vo.RoleVO;
8 | import org.springframework.beans.BeanUtils;
9 | import org.springframework.beans.factory.annotation.Autowired;
10 | import org.springframework.stereotype.Service;
11 |
12 | import java.util.ArrayList;
13 | import java.util.List;
14 |
15 | @Service
16 | public class RoleServiceImpl implements RoleService {
17 |
18 | @Autowired
19 | private RoleRepository roleRepository;
20 |
21 | @Override
22 | public ResponseVO findAllRoleVO() {
23 | List rolePOList = roleRepository.findAll();
24 | List roleVOList = new ArrayList<>();
25 | rolePOList.forEach(rolePO->{
26 | RoleVO roleVO = new RoleVO();
27 | BeanUtils.copyProperties(rolePO,roleVO);
28 | roleVOList.add(roleVO);
29 | });
30 | return ResponseVO.success(roleVOList);
31 | }
32 |
33 | @Override
34 | public Role findById(Integer id) {
35 | return roleRepository.findById(id).get();
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/com/unionman/springbootsecurityauth2/service/impl/UserServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.unionman.springbootsecurityauth2.service.impl;
2 |
3 | import com.unionman.springbootsecurityauth2.config.ServerConfig;
4 | import com.unionman.springbootsecurityauth2.domain.Token;
5 | import com.unionman.springbootsecurityauth2.dto.LoginUserDTO;
6 | import com.unionman.springbootsecurityauth2.dto.UserDTO;
7 | import com.unionman.springbootsecurityauth2.entity.Role;
8 | import com.unionman.springbootsecurityauth2.entity.User;
9 | import com.unionman.springbootsecurityauth2.enums.ResponseEnum;
10 | import com.unionman.springbootsecurityauth2.enums.UrlEnum;
11 | import com.unionman.springbootsecurityauth2.repository.UserRepository;
12 | import com.unionman.springbootsecurityauth2.service.RoleService;
13 | import com.unionman.springbootsecurityauth2.service.UserService;
14 | import com.unionman.springbootsecurityauth2.utils.BeanUtils;
15 | import com.unionman.springbootsecurityauth2.utils.RedisUtil;
16 | import com.unionman.springbootsecurityauth2.vo.LoginUserVO;
17 | import com.unionman.springbootsecurityauth2.vo.ResponseVO;
18 | import com.unionman.springbootsecurityauth2.vo.RoleVO;
19 | import com.unionman.springbootsecurityauth2.vo.UserVO;
20 | import org.springframework.beans.factory.annotation.Autowired;
21 | import org.springframework.stereotype.Service;
22 | import org.springframework.transaction.annotation.Transactional;
23 | import org.springframework.util.LinkedMultiValueMap;
24 | import org.springframework.util.MultiValueMap;
25 | import org.springframework.web.client.RestClientException;
26 | import org.springframework.web.client.RestTemplate;
27 |
28 | import java.util.ArrayList;
29 | import java.util.List;
30 | import java.util.concurrent.TimeUnit;
31 |
32 | import static com.unionman.springbootsecurityauth2.config.OAuth2Config.CLIENT_ID;
33 | import static com.unionman.springbootsecurityauth2.config.OAuth2Config.CLIENT_SECRET;
34 | import static com.unionman.springbootsecurityauth2.config.OAuth2Config.GRANT_TYPE;
35 |
36 | @Service
37 | public class UserServiceImpl implements UserService {
38 |
39 | @Autowired
40 | private UserRepository userRepository;
41 |
42 | @Autowired
43 | private RoleService roleService;
44 |
45 | @Autowired
46 | private RestTemplate restTemplate;
47 |
48 | @Autowired
49 | private ServerConfig serverConfig;
50 |
51 | @Autowired
52 | private RedisUtil redisUtil;
53 |
54 | @Override
55 | @Transactional(rollbackFor = Exception.class)
56 | public void addUser(UserDTO userDTO) {
57 | User userPO = new User();
58 | User userByAccount = userRepository.findUserByAccount(userDTO.getAccount());
59 | if(userByAccount != null){
60 | //此处应该用自定义异常去返回,在这里我就不去具体实现了
61 | try {
62 | throw new Exception("This user already exists!");
63 | } catch (Exception e) {
64 | e.printStackTrace();
65 | }
66 | }
67 | userPO.setCreatedTime(System.currentTimeMillis());
68 | //添加用户角色信息
69 | Role rolePO = roleService.findById(userDTO.getRoleId());
70 | userPO.setRole(rolePO);
71 | BeanUtils.copyPropertiesIgnoreNull(userDTO,userPO);
72 | userRepository.save(userPO);
73 | }
74 |
75 | @Override
76 | @Transactional(rollbackFor = Exception.class)
77 | public void deleteUser(Integer id) {
78 | User userPO = userRepository.findById(id).get();
79 | if(userPO == null){
80 | //此处应该用自定义异常去返回,在这里我就不去具体实现了
81 | try {
82 | throw new Exception("This user not exists!");
83 | } catch (Exception e) {
84 | e.printStackTrace();
85 | }
86 | }
87 | userRepository.delete(userPO);
88 | }
89 |
90 | @Override
91 | @Transactional(rollbackFor = Exception.class)
92 | public void updateUser(UserDTO userDTO) {
93 | User userPO = userRepository.findById(userDTO.getId()).get();
94 | if(userPO == null){
95 | //此处应该用自定义异常去返回,在这里我就不去具体实现了
96 | try {
97 | throw new Exception("This user not exists!");
98 | } catch (Exception e) {
99 | e.printStackTrace();
100 | }
101 | }
102 | BeanUtils.copyPropertiesIgnoreNull(userDTO, userPO);
103 | //修改用户角色信息
104 | Role rolePO = roleService.findById(userDTO.getRoleId());
105 | userPO.setRole(rolePO);
106 | userRepository.saveAndFlush(userPO);
107 | }
108 |
109 | @Override
110 | public ResponseVO> findAllUserVO() {
111 | List userPOList = userRepository.findAll();
112 | List userVOList = new ArrayList<>();
113 | userPOList.forEach(userPO->{
114 | UserVO userVO = new UserVO();
115 | BeanUtils.copyPropertiesIgnoreNull(userPO,userVO);
116 | RoleVO roleVO = new RoleVO();
117 | BeanUtils.copyPropertiesIgnoreNull(userPO.getRole(),roleVO);
118 | userVO.setRole(roleVO);
119 | userVOList.add(userVO);
120 | });
121 | return ResponseVO.success(userVOList);
122 | }
123 |
124 | @Override
125 | public ResponseVO login(LoginUserDTO loginUserDTO) {
126 | MultiValueMap paramMap = new LinkedMultiValueMap<>();
127 | paramMap.add("client_id", CLIENT_ID);
128 | paramMap.add("client_secret", CLIENT_SECRET);
129 | paramMap.add("username", loginUserDTO.getAccount());
130 | paramMap.add("password", loginUserDTO.getPassword());
131 | paramMap.add("grant_type", GRANT_TYPE[0]);
132 | Token token = null;
133 | try {
134 | //因为oauth2本身自带的登录接口是"/oauth/token",并且返回的数据类型不能按我们想要的去返回
135 | //但是我的业务需求是,登录接口是"user/login",由于我没研究过要怎么去修改oauth2内部的endpoint配置
136 | //所以这里我用restTemplate(HTTP客户端)进行一次转发到oauth2内部的登录接口,比较简单粗暴
137 | token = restTemplate.postForObject(serverConfig.getUrl() + UrlEnum.LOGIN_URL.getUrl(), paramMap, Token.class);
138 | LoginUserVO loginUserVO = redisUtil.get(token.getValue(), LoginUserVO.class);
139 | if(loginUserVO != null){
140 | //登录的时候,判断该用户是否已经登录过了
141 | //如果redis里面已经存在该用户已经登录过了的信息
142 | //我这边要刷新一遍token信息,不然,它会返回上一次还未过时的token信息给你
143 | //不便于做单点维护
144 | token = oauthRefreshToken(loginUserVO.getRefreshToken());
145 | redisUtil.deleteCache(loginUserVO.getAccessToken());
146 | }
147 | } catch (RestClientException e) {
148 | try {
149 | e.printStackTrace();
150 | //此处应该用自定义异常去返回,在这里我就不去具体实现了
151 | //throw new Exception("username or password error");
152 | } catch (Exception e1) {
153 | e1.printStackTrace();
154 | }
155 | }
156 | //这里我拿到了登录成功后返回的token信息之后,我再进行一层封装,最后返回给前端的其实是LoginUserVO
157 | LoginUserVO loginUserVO = new LoginUserVO();
158 | User userPO = userRepository.findUserByAccount(loginUserDTO.getAccount());
159 | BeanUtils.copyPropertiesIgnoreNull(userPO, loginUserVO);
160 | loginUserVO.setPassword(userPO.getPassword());
161 | loginUserVO.setAccessToken(token.getValue());
162 | loginUserVO.setAccessTokenExpiresIn(token.getExpiresIn());
163 | loginUserVO.setAccessTokenExpiration(token.getExpiration());
164 | loginUserVO.setExpired(token.isExpired());
165 | loginUserVO.setScope(token.getScope());
166 | loginUserVO.setTokenType(token.getTokenType());
167 | loginUserVO.setRefreshToken(token.getRefreshToken().getValue());
168 | loginUserVO.setRefreshTokenExpiration(token.getRefreshToken().getExpiration());
169 | //存储登录的用户
170 | redisUtil.set(loginUserVO.getAccessToken(),loginUserVO,TimeUnit.HOURS.toSeconds(1));
171 | return ResponseVO.success(loginUserVO);
172 | }
173 |
174 | /**
175 | * @description oauth2客户端刷新token
176 | * @param refreshToken
177 | * @date 2019/03/05 14:27:22
178 | * @author Zhifeng.Zeng
179 | * @return
180 | */
181 | private Token oauthRefreshToken(String refreshToken) {
182 | MultiValueMap paramMap = new LinkedMultiValueMap<>();
183 | paramMap.add("client_id", CLIENT_ID);
184 | paramMap.add("client_secret", CLIENT_SECRET);
185 | paramMap.add("refresh_token", refreshToken);
186 | paramMap.add("grant_type", GRANT_TYPE[1]);
187 | Token token = null;
188 | try {
189 | token = restTemplate.postForObject(serverConfig.getUrl() + UrlEnum.LOGIN_URL.getUrl(), paramMap, Token.class);
190 | } catch (RestClientException e) {
191 | try {
192 | //此处应该用自定义异常去返回,在这里我就不去具体实现了
193 | throw new Exception(ResponseEnum.REFRESH_TOKEN_INVALID.getMessage());
194 | } catch (Exception e1) {
195 | e1.printStackTrace();
196 | }
197 | }
198 | return token;
199 | }
200 |
201 |
202 | }
203 |
--------------------------------------------------------------------------------
/src/main/java/com/unionman/springbootsecurityauth2/utils/AssertUtils.java:
--------------------------------------------------------------------------------
1 | package com.unionman.springbootsecurityauth2.utils;
2 |
3 | public class AssertUtils {
4 | /**
5 | * @description 获取请求头的token
6 | * @param authToken
7 | * @return
8 | */
9 | public static String extracteToken(String authToken){
10 | String authTokenPrefix="Bearer";
11 | if(authToken.indexOf(authTokenPrefix)!=-1){
12 | return authToken.substring(7);
13 | }else {
14 | return authToken;
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/com/unionman/springbootsecurityauth2/utils/BeanUtils.java:
--------------------------------------------------------------------------------
1 | package com.unionman.springbootsecurityauth2.utils;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 | import org.springframework.beans.BeanWrapper;
5 | import org.springframework.beans.BeanWrapperImpl;
6 | import org.springframework.util.LinkedMultiValueMap;
7 | import org.springframework.util.MultiValueMap;
8 |
9 | import java.beans.BeanInfo;
10 | import java.beans.IntrospectionException;
11 | import java.beans.Introspector;
12 | import java.beans.PropertyDescriptor;
13 | import java.lang.reflect.Constructor;
14 | import java.lang.reflect.InvocationTargetException;
15 | import java.lang.reflect.Method;
16 | import java.util.*;
17 |
18 | /**
19 | * @description: bean工具类
20 | * @date 2019/02/21 09:22
21 | * @author Zhifeng.Zeng
22 | */
23 | @Slf4j
24 | public class BeanUtils {
25 |
26 | /**
27 | * 属性拷贝方法,忽略入参值为空
28 | * @author Zhifeng.Zeng
29 | * @param src
30 | * @param target
31 | */
32 | public static void copyPropertiesIgnoreNull(Object src, Object target){
33 | org.springframework.beans.BeanUtils.copyProperties(src, target, getNullPropertyNames(src));
34 | }
35 |
36 | private static String[] getNullPropertyNames (Object source) {
37 | final BeanWrapper src = new BeanWrapperImpl(source);
38 | PropertyDescriptor[] pds = src.getPropertyDescriptors();
39 |
40 | Set emptyNames = new HashSet();
41 | for(PropertyDescriptor pd : pds) {
42 | Object srcValue = src.getPropertyValue(pd.getName());
43 | if (srcValue == null) {
44 | emptyNames.add(pd.getName());
45 | }
46 | }
47 | String[] result = new String[emptyNames.size()];
48 | return emptyNames.toArray(result);
49 | }
50 |
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/com/unionman/springbootsecurityauth2/utils/RedisUtil.java:
--------------------------------------------------------------------------------
1 | package com.unionman.springbootsecurityauth2.utils;
2 |
3 | import com.alibaba.fastjson.JSON;
4 | import com.alibaba.fastjson.JSONObject;
5 | import lombok.extern.slf4j.Slf4j;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.data.redis.core.RedisTemplate;
8 | import org.springframework.stereotype.Component;
9 | import org.springframework.util.CollectionUtils;
10 |
11 | import java.util.List;
12 | import java.util.Map;
13 | import java.util.Set;
14 | import java.util.concurrent.TimeUnit;
15 |
16 | /**
17 | * @description: redis 工具类
18 | * @author: Rong.Jia
19 | * @date: 2018年6月13日 22:58:22
20 | */
21 | @Slf4j
22 | @Component
23 | public class RedisUtil {
24 |
25 | @Autowired
26 | private RedisTemplate redisTemplate;
27 |
28 |
29 | /**
30 | * @param key 键
31 | * @param time 时间(秒)
32 | * @return boolean
33 | * @description: 指定缓存失效时间
34 | */
35 | public boolean expire(String key, long time) {
36 | try {
37 | if (time > 0) {
38 | redisTemplate.expire(key, time, TimeUnit.SECONDS);
39 | }
40 | return true;
41 | } catch (Exception e) {
42 | log.error("class:RedisUtils method:expire() => Exception {}",e.getMessage());
43 | }
44 | return false;
45 | }
46 |
47 | /**
48 | * @param key 键 不能为null
49 | * @return 时间(秒) 返回0代表为永久有效
50 | * @description: 根据key 获取过期时间
51 | */
52 | public long getExpire(String key) {
53 | return redisTemplate.getExpire(key, TimeUnit.SECONDS);
54 | }
55 |
56 | /**
57 | * @param key 键
58 | * @return true 存在 false不存在
59 | * @description: 判断key是否存在
60 | */
61 | public boolean exists(String key) {
62 | try {
63 | return redisTemplate.hasKey(key);
64 | } catch (Exception e) {
65 | log.error("class:RedisUtils method:exists() => Exception {}",e.getMessage());
66 | }
67 | return false;
68 | }
69 |
70 | /**
71 | * @param key 可以传一个值 或多个
72 | * @description: 删除缓存
73 | */
74 | @SuppressWarnings("unchecked")
75 | public void deleteCache(String... key) {
76 | if (key != null && key.length > 0) {
77 | if (key.length == 1) {
78 | redisTemplate.delete(key[0]);
79 | } else {
80 | redisTemplate.delete(CollectionUtils.arrayToList(key));
81 | }
82 | }
83 | }
84 |
85 | public T get(String key, Class clazz, long expire) {
86 |
87 | Object value = redisTemplate.opsForValue().get(key);
88 | if (expire != -1L) {
89 | redisTemplate.expire(key, expire, TimeUnit.SECONDS);
90 | }
91 | return value == null ? null : fromJson(value, clazz);
92 | }
93 |
94 | public T get(String key, Class clazz) {
95 |
96 | return get(key, clazz, -1L);
97 | }
98 |
99 | /**
100 | * @param key 键
101 | * @return Object value
102 | * @description: 根据key获取value
103 | */
104 | public Object getValueByKey(String key) {
105 | return key == null ? null : redisTemplate.opsForValue().get(key);
106 | }
107 |
108 | /**
109 | * @param key 键
110 | * @param value 值
111 | * @param expire 时间(秒) time要大于0 如果expire小于等于0 将设置无限期
112 | * @return true成功 false失败
113 | * @description: 普通缓存放入
114 | */
115 | public void set(String key, Object value, long expire) {
116 | redisTemplate.opsForValue().set(key, value);
117 | if (expire != -1L) {
118 | redisTemplate.expire(key, expire, TimeUnit.SECONDS);
119 | }
120 | }
121 |
122 | /**
123 | * 普通缓存放入并设置时间
124 | *
125 | * @param key 键
126 | * @param value 值
127 | * @return true成功 false 失败
128 | */
129 | public void set(String key, Object value) {
130 | set(key, value, 3600L);
131 | }
132 |
133 | /**
134 | * 递增
135 | *
136 | * @param key 键
137 | * @param delta 要增加几(大于0)
138 | * @return
139 | */
140 | public long increasing(String key, long delta) {
141 | if (delta < 0) {
142 | log.error("class:RedisUtils method:increasing() => delta:{} delta must more than 0",delta);
143 | }
144 | return redisTemplate.opsForValue().increment(key, delta);
145 | }
146 |
147 | /**
148 | * 递减
149 | *
150 | * @param key 键
151 | * @param delta 要减少几(小于0)
152 | * @return
153 | */
154 | public long decr(String key, long delta) {
155 | if (delta < 0) {
156 | log.error("class:RedisUtils method:decr() => delta:{} delta must more than 0",delta);
157 | }
158 | return redisTemplate.opsForValue().increment(key, -delta);
159 | }
160 |
161 | //================================Map=================================
162 |
163 | /**
164 | * HashGet
165 | *
166 | * @param key 键 不能为null
167 | * @param item 项 不能为null
168 | * @return 值
169 | */
170 | public Object hget(String key, String item) {
171 | return redisTemplate.opsForHash().get(key, item);
172 | }
173 |
174 | /**
175 | * 获取hashKey对应的所有键值
176 | *
177 | * @param key 键
178 | * @return 对应的多个键值
179 | */
180 | public Map