Microservices Architecture

  • Gateway: routes user requests to specified services and forwards Session information contained in front-end cookies.
  • User services: User login Authentication, User authorization, User Management Redis Session Management
  • Other services: rely on user information in Redis for interface request verification

User – role – permission table structure design

  • Permission table A permission table controls a single function, such as user management and resource management, in the smallest granularity. Example:
id

authority

description

1

ROLEADMINUSER

Managing All Users

2

ROLEADMINRESOURCE Managing All Resources

3

ROLEA1

Permission to access a ServiceA interface

4

ROLEA2

Access to another interface of ServiceA
5

ROLEB1

Permission to access an interface of ServiceB

6

ROLEB2

Access to another interface of ServiceB
  • Role – Permission table User-defined roles that combine various permissions. For example, the super administrator has all permissions. The table structure is as follows:
id

name

authority_ids
1

Super administrator 6

2

Administrator A

3, 4

3

The administrator B

5 or 6

4

The average user

NULL

  • User-role table The user is bound to one or more roles, that is, to assign various permissions. Example 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>Copy the code

Application configuration Application. yml Example:

# Spring configuration Spring Session. The Session. Store - type = redis server. The servlet. The Session. The persistent = true Server. The servlet. Session. Timeout = 7 d server. The servlet. Session. Cookies. The Max - age = 7 d # Redis configuration spring. Redis. Host = < Redis - host > Port =6379 # MySQL config 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>Copy the code

User Login Authentication and 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, // Query user authority List<SimpleGrantedAuthority> userAuthorities = userService.getSimpleGrantedAuthority(user.getId()); return new UsernamePasswordAuthenticationToken(user.getId(), null, userAuthorities); } throw new AuthenticationServiceException (" login failed "); 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()); } / check username and password * * * * / 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); } / custom authentication filter * * * * / private CustomAuthenticationFilter CustomAuthenticationFilter () {CustomAuthenticationFilter authenticationFilter = new CustomAuthenticationFilter(LOGIN_URL, userService); return authenticationFilter; }}Copy the code

Other Service Design

Application configuration Application. yml Example:

Redis. host=<redis-host> spring.redis.port=6379Copy the code

Global Security Configuration

@EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .anyRequest().authenticated() .and() .csrf().disable(); }}Copy the code

Obtaining user authentication information

After the success of the user through a user login, user information will be cached to Redis, cached information and CustomAuthenticationFilter attemptAuthentication () method returns the object, as above so, The object returned is new UsernamePasswordAuthenticationToken (user getId (), null, userAuthorities), Redis caches the user ID and authorities.

UsernamePasswordAuthenticationToken constructor of the first parameter is the Object, so you can customize the cache Object.

The methods to obtain such information of users in each module of micro-service are as follows:

@GetMapping() public WebResponse test(@AuthenticationPrincipal UsernamePasswordAuthenticationToken authenticationToken){ / / slightly}Copy the code

Access control

  • Enable method-based permission annotations
@SpringBootApplication @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); }}Copy the code

  • Simple permission check

    For example, the interface for deleting a role can be owned onlyROLE_ADMIN_USERPermission for user access.
/** * delete roles */ @postmapping ("/delete") @preauthorize ("hasRole('ADMIN_USER')") public WebResponse deleteRole(@requestBody) RoleBean RoleBean){//Copy the code

@preauthorize (“hasRole(‘)”) applies to each module in the microservice

  • Custom permission verification

    As shown above,hasRole()The method is embedded in Spring Security. If you need to customize it, you can use expression-based Access Control.
/ * * * * / custom validation Service @ Service public class CustomService {public Boolean check (UsernamePasswordAuthenticationToken authenticationToken, String extraParam){// Omitted}} /** * Delete roles */ @postmapping () @preauthorize ("@customService.check(authentication, Public WebResponse custom(@requestBody userBean userBean){Copy the code

Authentication is a built-in object. # get the value of the input parameter

  • Dynamic change of any user permission In principle, user permission information is stored in Redis. To change user permission, you need to operate Redis. For example:
@Service @AllArgsConstructor public class HttpSessionService<S extends Session> { private final FindByIndexNameSessionRepository<S> sessionRepository; /** * Reorities 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); }); }}Copy the code

Modify the user permissions, simply invoke httpSessionService. ResetAuthorities () method can, immediate effect.

© copyright belongs to the author, reprint or content cooperation please contact the author

● Spring Cloud Gateway – Start fast

● APM tools searched around and found SkyWalking was the one for me

● Spring Boot injects static variables from external configuration into the application

● Convert HTML to PDF new pose

● Java calls the Docker API using UnixSocket

● Fastjson fatal flaw

● Service mesh-GRPC Local integrated remote Service

● Use Thymeleaf to render HTML dynamically

● Fastjson fatal flaw

● Spring Boot 2 integrates log4J2 logging framework

● Java interview key points summary set of core reference answers

● Java interview key points summary of the framework of reference answers

● How to protect your password

● Spring Boot RabbitMQ – Priority queue

Original link: https://mp.weixin.qq.com/s?__biz=MzU0MDEwMjgwNA==&mid=2247486167&idx=2&sn=76dba01d16b7147c9b1dfb7cbf2d8d28&chksm=fb3f132 ccc489a3ad2ea05314823d660c40e8af90dcd35800422899958f98b4a258d23badba8&token=280305379&lang=zh_CN#rd

This article is published by OpenWrite!