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_USER
Permission 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!