[Permission management platform] Day-02 project construction and Shiro related configuration

Hits: 0

[Permission Management Platform] Project Development Day—02

🏡 Blog Homepage: Pai Daxing

⛳️ Welcome to follow 🐳 Like 🎒 Favorites ✏️ Comment

🎢 This article was originally edited by Pai Daxing

🚧 Series of columns: Projects are built from 0

🎈 This series of projects are all open source and free to learn and use from design to implementation. Let’s [pursue] the ideal together. Welcome to supervise the development of punch cards!

Today’s project construction progress

🍌Permission data design & interface design

🍇 Permission data design

🍑 Interface Design

​ In normal development, we habitually call the interface we wrote Api, so this time we simply designed the interface of this project as /api/xxx/xxx(in fact, it is not a design at all ♨️).

🍍 Actual encoding

🍔 Swagger related configuration

​isSwagger a canonical and complete framework for generating, describing, invoking and visualizing RestFulstyle Webservices. The overall goal is to have the client and filesystem update at the same rate as the server. File methods, parameters and models are tightly integrated into the server-side code, allowing the API to be always in sync.

import dependencies

<dependency>
  <groupId>io.springfox</groupId>
  <artifactId>springfox-swagger2</artifactId>
  <version>2.9.2</version>
</dependency>
<dependency>
  <groupId>io.springfox</groupId>
  <artifactId>springfox-swagger-ui</artifactId>
  <version>2.9.2</version>
</dependency>

Related configuration

@Configuration
public class SwaggerConfig {

    @Value("${swagger2.enable}")
    private boolean enable;

    @Bean
    public Docket docket(){
        /*
        * This is for us to add header information (token) when we use swagger to test the interface
        * After logging in, return the Token information and add the Token to access other interfaces that require certain permissions/roles
        * */
        List<Parameter> pars = new ArrayList<Parameter>();
        ParameterBuilder tokenPar = new ParameterBuilder();
        tokenPar.name( "authorization" ).description( "Please enter Token information" )
                .modelRef(new ModelRef("string"))
                .parameterType("header")
                .required(false);
        /*
        *When there are more than one, just add it directly to pars
        * */
        pars.add(tokenPar.build());
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.pdx.controller"))
                .paths(PathSelectors.any())
                .build()
                .globalOperationParameters(pars)
                .enable(enable);
    }
    private ApiInfo apiInfo () {
         return  new ApiInfoBuilder()
                .title( "Paida Star Rights Management Platform" )
                .description( "Paida Star Rights Management Platform" )
                .termsOfServiceUrl("")
                .version("1.0")
                .build();
    }
}

🍰  [Shiro] framework basic construction related configuration

​ So what is Shiroit? Let’s take a brief look at this security framework:

​FrameworkShiro is Apachethe next Java security framework, which has SpringSecuritythe same effect as , SpringSecurityand Shirohas more prominent features compared to:

  • convenient
  • easy to use
  • Support annotation development
🍕 Shiro main features:

Three core components: Subject SecurityManagerand Realms

  • Subject:That is, the “current operating user”. However, in Shiro, Subjectthe concept doesn’t just refer to people, but can also be third-party processes, background accounts, or other similar things. It simply means “what is currently interacting with the software”.
  • SecurityManager:It is Shirothe core of the framework, Shiro manages internal component instances through SecurityManager, and provides various services for security management through it.
  • Realm:Realm acts as a “bridge” or “connector” between Shiro and application security data. That is, when authentication (login) and authorization (access control) are performed on a user, information about the user and their permissions is looked up Shirofrom the app’s configuration .Realm

If you don’t know shirothe authentication mechanism, please move: Send a star to show you Shiro’s authentication mechanism in ten minutes

🍫 Learn about Jwt

​(JWT full name: Json Web Token) is an open standard (RFC 7519) that defines a compact, self-contained way to securely transmit information between parties as JSON objects. This information can be verified and trusted because it is digitally signed.

Jwt’s data structure

JwtIt is usually a string, divided into three parts, and each part is "."separated by:

xxxxx .yyyyy .zzzzz

What three parts does Jwt include?

  • Header

JWTThe first part is the header part, which is an object describing the metadata of the JWT Json, usually as follows.

{
    "alg": "HS256",
    "typ": "JWT"
}

algThe attribute indicates the algorithm used by the signature, the default is HMAC SHA256(written as HS256), the typattribute indicates the type of the JWTtoken, and the token is written uniformly as JWT.

  • Payload

JWTThe second part is Payloadalso an Jsonobject, in addition to containing the data that needs to be passed, there are seven default fields to choose from.

They are, iss:issuer, exp:expiration time, sub:subject, aud:user, nbf:not available until then, iat:published time, jti: JWT IDto identify the JWT.

  • Signature

So how is it generated? First of all, you need to specify one secret, which should secretonly be stored in the server and ensure that other users cannot know it. HeaderThe sum Payloadis then calculated using the algorithm specified by the Header , and a signature hash is obtained. That is Signature.

🍨 Advantages

  • jsonThe format is universal, so it JWTcan be supported across languages, such as Java、JavaScript、PHP、Nodeand so on.
  • Can be used to Payloadstore some non-sensitive information.
  • Easy to transmit, JWTsimple in structure, and small in byte occupancy.
  • No need to save session information on the server side, easy to apply extension.
🍒 Shiro configuration in action

import dependencies

<dependency>
  <groupId>org.apache.shiro</groupId>
  <artifactId>shiro-spring</artifactId>
  <version>1.4.1</version>
</dependency>

Custom Realm class

@Slf4j
public class CustomRealm extends AuthorizingRealm {

    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof CustomUsernamePasswordToken;
    }
    /**
     * Authorization mechanism
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        return null;
    }
    /**
     * Authentication mechanism
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        CustomUsernamePasswordToken usernamePasswordToken = (CustomUsernamePasswordToken) token;
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(usernamePasswordToken.getPrincipal(), usernamePasswordToken.getCredentials(), getName());
        return info;
    }
}

Customize Shiro’s default encryption method

@Slf4j
public class CustomHashedCredentialsMatcher extends HashedCredentialsMatcher {

    @Autowired
    private RedisService redisService;
    /**
     * encrypted match
     * @param token
     * @param info
     * @return
     */
    @Override
    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
        CustomUsernamePasswordToken usernamePasswordToken = (CustomUsernamePasswordToken) token;
        String accessToken = (String) usernamePasswordToken.getCredentials();
        String userId = JwtTokenUtil.getUserId(accessToken);
        log.info ( "doCredentialsMatch.....userId=>{}" ,userId);
         //Determine whether the user is deleted 
        if (redisService.hasKey(Constant.DELETE_USER_KEY+userId)){
             throw  new BusinessException(BaseResponseCode.ACCOUNT_HAS_DELETE_ERROR) ;
        }
        //Determine whether the user is locked 
        if (redisService.hasKey(Constant.ACCOUNT_LOCK_KEY+userId)){
             throw  new BusinessException(BaseResponseCode.ACCOUNT_LOCKED);
        }
        //Determine whether the user is logged out 
        if (redisService.hasKey(Constant.JWT_ACCESS_TOKEN_BLACKLIST+userId)){
             throw  new BusinessException(BaseResponseCode.TOKEN_ERROR);
        }
        if (!JwtTokenUtil.validateToken(accessToken)){
            throw new BusinessException(BaseResponseCode.TOKEN_PAST_DUE);
        }
        return true;
    }
}

Custom UsernamePasswordToken class

public class CustomUsernamePasswordToken extends UsernamePasswordToken {
    private String jwtToken;

    public CustomUsernamePasswordToken(String jwtToken){
        this.jwtToken = jwtToken;
    }

    @Override
    public Object getPrincipal() {
        return jwtToken;
    }

    @Override
    public Object getCredentials() {
        return jwtToken;
    }
}

The freshly released code will be updated to the Giteewarehouse in time

The above code is part of the implementation, if you want to know the full configuration, please go to: Paidaxing’s Gitee warehouse

That’s it for today’s workload! I hope that the big guys can supervise and send Daxing to build the platform from 0 step by step!

Leave a Reply

Your email address will not be published.