Micro Services Architecture
- Gateway: route user requests to the designated service, forwarding Cookie Session information contained in the distal end;
- User services: user login authentication (Authentication), user authorization (Authority), user management (Redis Session Management)
- Other services: user-dependent information Redis request verification interface
User - role - permission table structure design
- Permission table
permissions table control the individual functions of the minimum particle size, such as user management, resource management, configuration example table:
id | authority | description |
---|---|---|
1 | ROLE_ADMIN_USER | Manage all users |
2 | ROLE_ADMIN_RESOURCE | Management of all resources |
3 | ROLE_A_1 | Access to an interface of the ServiceA |
4 | ROLE_A_2 | Another privilege of access to an interface ServiceA |
5 | ROLE_B_1 | ServiceB access to certain interfaces |
6 | ROLE_B_2 | Another privilege of access to an interface ServiceB |
- Roles - Permissions table
custom roles, various combinations of rights, such as the Super Administrator has all rights, table structure Example:
id | name | authority_ids |
---|---|---|
1 | Super Admin | 1,2,3,4,5,6 |
2 | A administrator | 3,4 |
3 | Administrator B | 5,6 |
4 | general user | NULL |
- User - role table
the user is bound to one or more roles, i.e., allocating the various rights, the exemplary table structure:
user_id | role_id |
---|---|
1 | 1 |
1 | 4 |
2 | 2 |
User Service Design
Maven dependencies (all services)
<!-- Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- Spring Session Redis -->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
Application Configuration application.yml
example:
# Spring Session 配置
spring.session.store-type=redis
server.servlet.session.persistent=true
server.servlet.session.timeout=7d
server.servlet.session.cookie.max-age=7d
# Redis 配置
spring.redis.host=<redis-host>
spring.redis.port=6379
# MySQL 配置
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://<mysql-host>:3306/test
spring.datasource.username=<username>
spring.datasource.password=<passowrd>
User login authentication (authentication) and authorization (authority)
Slf4j
public class CustomAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
private final UserService userService;
CustomAuthenticationFilter(String defaultFilterProcessesUrl, UserService userService) {
super(new AntPathRequestMatcher(defaultFilterProcessesUrl, HttpMethod.POST.name()));
this.userService = userService;
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
JSONObject requestBody = getRequestBody(request);
String username = requestBody.getString("username");
String password = requestBody.getString("password");
UserDO user = userService.getByUsername(username);
if (user != null && validateUsernameAndPassword(username, password, user)){
// 查询用户的 authority
List<SimpleGrantedAuthority> userAuthorities = userService.getSimpleGrantedAuthority(user.getId());
return new UsernamePasswordAuthenticationToken(user.getId(), null, userAuthorities);
}
throw new AuthenticationServiceException("登录失败");
}
/**
* 获取请求体
*/
private JSONObject getRequestBody(HttpServletRequest request) throws AuthenticationException{
try {
StringBuilder stringBuilder = new StringBuilder();
InputStream inputStream = request.getInputStream();
byte[] bs = new byte[StreamUtils.BUFFER_SIZE];
int len;
while ((len = inputStream.read(bs)) != -1) {
stringBuilder.append(new String(bs, 0, len));
}
return JSON.parseObject(stringBuilder.toString());
} catch (IOException e) {
log.error("get request body error.");
}
throw new AuthenticationServiceException(HttpRequestStatusEnum.INVALID_REQUEST.getMessage());
}
/**
* 校验用户名和密码
*/
private boolean validateUsernameAndPassword(String username, String password, UserDO user) throws AuthenticationException {
return username == user.getUsername() && password == user.getPassword();
}
}
@EnableWebSecurity
@AllArgsConstructor
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private static final String LOGIN_URL = "/user/login";
private static final String LOGOUT_URL = "/user/logout";
private final UserService userService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers(LOGIN_URL).permitAll()
.anyRequest().authenticated()
.and()
.logout().logoutUrl(LOGOUT_URL).clearAuthentication(true).permitAll()
.and()
.csrf().disable();
http.addFilterAt(bipAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.rememberMe().alwaysRemember(true);
}
/**
* 自定义认证过滤器
*/
private CustomAuthenticationFilter customAuthenticationFilter() {
CustomAuthenticationFilter authenticationFilter = new CustomAuthenticationFilter(LOGIN_URL, userService);
return authenticationFilter;
}
}
Other Design Services
Application Configuration application.yml
example:
# Spring Session 配置
spring.session.store-type=redis
# Redis 配置
spring.redis.host=<redis-host>
spring.redis.port=6379
Global Security Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.csrf().disable();
}
}
User authentication information acquisition
After successful login user service by the user, the user information is cached to Redis, cached information and CustomAuthenticationFilter
the attemptAuthentication()
method returns the object related, as it is, the object returned is new UsernamePasswordAuthenticationToken(user.getId(), null, userAuthorities)
that Redis caching the user's ID and the user's authority (authorities).
UsernamePasswordAuthenticationToken
The first argument to the constructor is Object object, the object can be custom cache.
Obtaining the information of the user service in the micro modules as follows:
@GetMapping()
public WebResponse test(@AuthenticationPrincipal UsernamePasswordAuthenticationToken authenticationToken){
// 略
}
Access control
- Enable permissions annotation-based approach
@SpringBootApplication
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
- Simple check permissions
for example, delete roles interface, allowing only haveROLE_ADMIN_USER
user rights to access.
/**
* 删除角色
*/
@PostMapping("/delete")
@PreAuthorize("hasRole('ADMIN_USER')")
public WebResponse deleteRole(@RequestBody RoleBean roleBean){
// 略
}
@PreAuthorize("hasRole('<authority>')")
It can act on the micro-service modules
- Custom permission checking
indicated above,hasRole()
is embedded Spring Security, For custom, you may use Expression-Based Access Control, Example:
/**
* 自定义校验服务
*/
@Service
public class CustomService{
public boolean check(UsernamePasswordAuthenticationToken authenticationToken, String extraParam){
// 略
}
}
/**
* 删除角色
*/
@PostMapping()
@PreAuthorize("@customService.check(authentication, #userBean.username)")
public WebResponse custom(@RequestBody UserBean userBean){
// 略
}
authentication
Belonging to the built-in objects,#
obtain the value of the parameter
- Dynamic modification of any user rights
on principle, information stored in the user's permissions Redis, modify user permissions will need to operate Redis, example:
@Service
@AllArgsConstructor
public class HttpSessionService<S extends Session> {
private final FindByIndexNameSessionRepository<S> sessionRepository;
/**
* 重置用户权限
*/
public void resetAuthorities(Long userId, List<GrantedAuthority> authorities){
UsernamePasswordAuthenticationToken newToken = new UsernamePasswordAuthenticationToken(userId, null, authorities);
Map<String, S> redisSessionMap = sessionRepository.findByPrincipalName(String.valueOf(userId));
redisSessionMap.values().forEach(session -> {
SecurityContextImpl securityContext = session.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
securityContext.setAuthentication(newToken);
session.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, securityContext);
sessionRepository.save(session);
});
}
}
Modify user privileges, simply call the httpSessionService.resetAuthorities()
method can, with immediate effect.
© copyright reserved by the authors, reprint please contact the author or content partners
● the Spring Cloud Gateway - Quick Start
● APM tool looking around and found SkyWalking is my true love
● The HTML into PDF new posture
● the Java Docker API calls using UnixSocket
● Service Mesh - GRPC local FBI remote service
● Use Thymeleaf dynamic rendering HTML
● the Spring integration log4j2日志框架the Boot 2
● core Java chapter sets off point summary of the interview on Answers
● framework for Java interview clearance papers set of reference points are summarized answers
● the Spring Security combat dry goods: how to protect user passwords
● the Spring the Boot RabbitMQ - priority queue
Original link: https: //mp.weixin.qq.com/s __biz = MzU0MDEwMjgwNA == & mid = 2247486167 & idx = 2 & sn = 76dba01d16b7147c9b1dfb7cbf2d8d28 & chksm = fb3f132ccc489a3ad2ea05314823d660c40e8af90dcd35800422899958f98b4a258d23badba8 & token = 280305379 & lang = zh_CN # rd?
This article from the blog article multiple platforms OpenWrite release!