Project introduction

When we develop projects, there is always some code or configuration that can be shared between projects, and it is not necessary to copy and paste the code and change it every time we create a new project. So I did a Poseidon-boot-starter project that was based on spring-Boot’s starter feature, so it only worked for Spring-Boot projects. The project integrates the following functions:

  • Abnormal notice
  • Access configuration
  • Idempotent lock
  • The log configuration
  • User operation logs are recorded
  • Query interface generalization

Project address: github.com/muggle0/pos…

Here’s how this component is used in our Spring-boot project.

First we need to download this project:

git clone https://github.com/muggle0/poseidon-boot-starter.gitCopy the code

Then install to our local warehouse or private cloud:

cd poseidon-boot-starter

mvn installCopy the code

Introduce dependencies in the Spring Boot project after installation:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-autoconfigure</artifactId>
 </dependency>Copy the code

Then do some basic configuration:

poseidon.auto=true
poseidon.static-path=/**/*.*
poseidon.ignore-path=/**
logging.config=classpath:poseidon-logback.xml
log.dir=logs
logging.level.com.muggle=debug
spring.profiles.include=refresh
Copy the code

Auto configuration is disabled by default. Poseidon. Auto =true is used to enable the function. We must implement two interfaces and injected into the spring container — com. Muggle. Poseidon. Store. SecurityStore and com. The muggle. Poseidon. Service. TokenService. Poseidon. static-path is a static resource path matched by Ant. Urls matching this rule will not be blocked by permission filters. Poseidon. ignored-path is an authentication ignore rule, and urls matching this rule will not participate in authentication and are directly allowed. Logging.config = CLASspath :poseidon-logback. XML uses the logback configuration strategy in poseidon-boot-starter (colorful black). If this configuration is used, you must specify the log.dir log file output path. Logging.level.com.muggle=debug specifies the package name as debug. Spring.profiles. Include =refresh When this profile is specified, all urls of the current project are fetched and handed to tokenService for processing. There are other functions that are not enabled by default, which are described in the source code interpretation.

The source code interpretation

As mentioned earlier, this project is based on the Starter function of Springboot. The principle is that a springboot custom VERSION of SPI will not be introduced here, but I will focus on how to use it in the project.

In meta-INF /spring.factories, you specify which classes to inject:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.muggle.poseidon.auto.ExpansibilityConfig,\
com.muggle.poseidon.auto.SecurityAutoConfig,\
com.muggle.poseidon.handler.web.WebUrlHandler,\
com.muggle.poseidon.handler.web.WebResultHandlerCopy the code

ExpansibilityConfig is the reserved configuration class but is not used. SecurityAutoConfig is the integrated configuration of Spring-Security. WebUrlHandler is used to handle specific urls. WebResultHandler is a unified exception handling configuration. ConditionalOnProperty(prefix = “Poseidon “, name = “auto”, havingValue = “true”, MatchIfMissing = false) to control whether it is automatically configured. The source code details of configuration classes are not covered here. The following is the interpretation of the source code for each function.

security

The project integrates Security and rewrites handler and authentication-related classes to return json and retrieve tokens from the request header. First we look at which processors are written:

  • com.muggle.poseidon.handler.security.PoseidonAccessDeniedHandlerAuthentication failure handler;
  • com.muggle.poseidon.handler.security.PoseidonAuthenticationFailureHandlerLogon failure handler;
  • com.muggle.poseidon.handler.security.PoseidonAuthenticationSuccessHandlerLogin success handler;
  • com.muggle.poseidon.handler.security.PoseidonLoginUrlAuthenticationEntryPointNot logged in processor;
  • com.muggle.poseidon.handler.security.PoseidonLogoutSuccessHandlerLogout success handler.

The above processors all return JSON data. If you need to modify the JSON format or change the redirection mode, you need to manually find the relevant processors to modify. Because this part of the related work (such as redirects or prompts) can be handled in the front end, it is not extended here.

Then the token filter com. Muggle. Poseidon. Filter. SecurityTokenFilter, the filter will be first obtained from the request header token, if get failure will get token from cookies, the key is token, . After the access to the token calls securityStore getUserdetail (String token) get a populated UserDetails, therefore, how to retrieve the user information to users via the token to extension, you can directly read from the database, Either it is read from the cache, or it is generated by parsing tokens, as is the case with JWT. In the following authentication process. The GrantedAuthority Collection and URL are retrieved from the UserDetails and passed to rooleMatch(Collection
authorities, String path) extends GrantedAuthority> authorities, String path) specifies the authentication function. The authentication scheme here also needs to be realized by the user, and the authentication scheme must be realized by matching the URL, so how to match the design scheme is a lot, here provide several ideas:

  1. When configuringspring.profiles.include=refreshGet all urls and associated Swagger comments in the project. toTokenService.processUrl(List<AuthUrlPathDO> list)You can save it to the database for subsequent authentication.
  2. You can set up a set of URL naming rules when authentication andGrantedAuthorityThrough direct matching, we can directly determine which users have access to the rules.
  3. When the front end makes a request, it takes a parameter at the end of the URL to specify which roles are accessible (insecure, authentication can be skipped by forging the request).

There are other related methods in TokenService and SecurityStore, such as login and logout, that are not covered here, see the source notes.

Unified Exception Handling

The unified exception handling class is WebResultHandler, which defines a strategy for handling exception information. If you don’t want these policies you can simply delete them or re-inject an exception handler yourself. If you want to extend them, you can refer to the example in the readme.md document in the project:

@RestControllerAdvice @Configuration public class MyWebResultHandler extends WebResultHandler { private static final Logger log = LoggerFactory.getLogger(OAwebResultHandler.class); @ExceptionHandler({ConstraintViolationException.class}) public ResultBean MethodArgumentNotValidException (ConstraintViolationException e, it the req) {log. The error (" failed the calibration parameters ", e); ResultBean error = ResultBean.error(e.getConstraintViolations().iterator().next().getMessage()); return error; }}Copy the code

One thing to note is that if an unknown exception occurs in our project, it should be taken seriously, so an event is thrown when an unknown exception occurs. Users can register listeners to listen for this event and notify developers when unknown exceptions occur. Example:

@Component public class ExceptionListener implements ApplicationListener<ExceptionEvent> { @Override public void onApplicationEvent(ExceptionEvent event) { String message = event.getMessage(); // TODO will send exception information to the mailbox, etc., to inform the developer of the system exception, as soon as possible to deal with. }}Copy the code

Request logs and idempotent locks

To use the request logging feature, you need to implement the DistributedLocker interface and register with the Spring container to enable the logging aspect. We then add @interfaceAction to the method we want to intercept. When we request this method, the request parameters will be entered into the log at the info level.

The INFO com. Muggle. Poseidon. Aop. RequestAspect - "" "" "" request log user name: User not logged in Url = / user/regester. Jsonmethod = POSTip = 127.0.0.1 host = 127.0.0.1 port = 57180 classmethod = com. The muggle. Poseidon. Oa. Controller. The user Controller.regesterparamters [ (OaUserVO(gender=1, username=muggle, password=xxxxxx, email=null, imgUrl=null)) ]Copy the code

Idempotent interception @interfaceAction (Idempotent = true,message = “request too frequent, please try again later “) Message is the intercepted message, expertime is the idempotent lock duration. After interception is enabled, a key is concatenated. String key = “Lock: IDEmpotent :” + Request.getrequestURI () + “:” + username + “:” + RequestUtils.getIP(request); Then call DistributedLocker. Trylock (String key, Long express) methods are locked, express parameters is annotations on configuration expertime, locking the way users need to realize, you can use redis, Zookeeper, or cache to lock.

Some users may want to be able to store the requested information in the database. I also provide an extension interface: As long as the RequestLogProcessor implements this interface and registers with Spring, you can get the request information in the recordBefore method and the return value in the recordAfterReturning method. Note that if the method throws an exception, You don’t get the return value. You need to modify the source code to add an exception section method. The exception section method is annotated with @afterthrowing.

The log configuration

TXT and poseidon-logback. XML. If you do not like the banner and want to remove it, you only need to add a banner. TXT to your project to overwrite it.

Poseidon-logback. XML is a configuration for log formats, etc., enabled with logging.config= CLASspath :poseidon-logback. XML, Dir =/temp/ XXX. After this configuration is enabled, you can see colorful black colors on the console. If you do not like this color, you can modify it according to the comments in the configuration file.

Query configuration

Make query configuration this function is to reduce the usual development write query interface development cost, this function itself is combined with mybatis pageHelper plug-in use, if you do not use this plug-in, you will not enjoy this benefit.

Since the query requirements vary from company to company, I’ve only done a top-level abstraction here. Specific query strategies still need to be implemented by developers, and the expansibility is reserved. Here are the ideas for this feature.

Query at the top of the bean abstraction for com. Muggle. Poseidon. Base. BaseQuery, it defines some general properties of the query. Then in com. Muggle. Poseidon. Aop. QueryAspect intercept in the query methods, blocking rule is the class name must end with the Controller, the must is a subclass of BaseQuery refs.

This section is not registered, you need to register it manually:

    @Bean
    QueryAspect getQueryAspect(){
        return new QueryAspect();
    }Copy the code

The query parameters are converted in doBefore(JoinPoint JoinPoint) of the slice, and the returned values are processed again in doAfterReturning(JoinPoint JoinPoint, Object Result). Actually use small partners and scale according to project requirements.

Encapsulation of some base classes

Com.muggle. Poseidon. Util is a collection of tools that you can add and remove as needed. Com. Muggle. Poseidon. Com under the base package. The muggle. Poseidon. Base. ResultBean is the return value of the controller layer of the bean encapsulation. Under the Exception package is the top-level abstract class for custom exceptions.

conclusion

At present, the project has only released the BETA version, and no new functions will be added to this version later. When the version is stable, I will release a REALSE version based on this version. If you find any bugs, suggestions for improvement, or new requirements for this project, please be sure to contact me. It is not easy to lift the code, so click star to support it.

Click here to follow my blog