SpringBoot e-Commerce project mall (25K + STAR) address: github.com/macrozheng/…

Abstract

Those of you who have studied my Mall project should know that the mall-admin module uses SpringSecurity+JWT to implement login authentication, while the mall-portal module uses SpringSecurity’s session-based default mechanism to implement login authentication. Many friends cannot find the login interface of mall-Portal. Recently, I unified the login authentication of these two modules, which are implemented in the form of SpringSecurity+JWT. This is done by extracting the general logic of login authentication into the mall security module. Let’s talk about how to use the Mall Security module for login authentication. It only takes four steps.

Integration steps

Here we take the mall- Portal transformation as an example to talk about how to achieve it.

  • First, add the module that requires login authenticationmall-securityRely on:
<dependency>
    <groupId>com.macro.mall</groupId>
    <artifactId>mall-security</artifactId>
</dependency>
Copy the code
  • Second, add the MallSecurityConfig configuration class and inheritmall-securityAnd an implementation class for the UserDetailsService interface to get logged-in user details:
/** * Created by macro on 2019/11/5. */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class MallSecurityConfig extends SecurityConfig {

    @Autowired
    private UmsMemberService memberService;

    @Bean
    public UserDetailsService userDetailsService(a) {
        // Obtain the login user information
        returnusername -> memberService.loadUserByUsername(username); }}Copy the code
  • Step 3: Configure the resource path that does not need security protection in application.yml:
secure:
  ignored:
    urls: # Secure path whitelist
      - /swagger-ui.html
      - /swagger-resources/**
      - /swagger/**
      - /**/v2/api-docs
      - /**/*.js
      - /**/*.css
      - /**/*.png
      - /**/*.ico
      - /webjars/springfox-swagger-ui/**
      - /druid/**
      - /actuator/**
      - /sso/**
      - /home/**
Copy the code
  • Step 4: Implement the interface for logging in and refreshing tokens in UmsMemberController:
/** * Created by macro on 2018/8/3. */
@Controller
@Api(tags = "UmsMemberController", description = "Member Login and Registration Management")
@RequestMapping("/sso")
public class UmsMemberController {
    @Value("${jwt.tokenHeader}")
    private String tokenHeader;
    @Value("${jwt.tokenHead}")
    private String tokenHead;
    @Autowired
    private UmsMemberService memberService;

    @ApiOperation("Member Login")
    @RequestMapping(value = "/login", method = RequestMethod.POST)
    @ResponseBody
    public CommonResult login(@RequestParam String username, @RequestParam String password) {
        String token = memberService.login(username, password);
        if (token == null) {
            return CommonResult.validateFailed("Wrong username or password");
        }
        Map<String, String> tokenMap = new HashMap<>();
        tokenMap.put("token", token);
        tokenMap.put("tokenHead", tokenHead);
        return CommonResult.success(tokenMap);
    }

    @ApiOperation(value = "Refresh token")
    @RequestMapping(value = "/refreshToken", method = RequestMethod.GET)
    @ResponseBody
    public CommonResult refreshToken(HttpServletRequest request) {
        String token = request.getHeader(tokenHeader);
        String refreshToken = memberService.refreshToken(token);
        if (refreshToken == null) {
            return CommonResult.failed("Token has expired!");
        }
        Map<String, String> tokenMap = new HashMap<>();
        tokenMap.put("token", refreshToken);
        tokenMap.put("tokenHead", tokenHead);
        returnCommonResult.success(tokenMap); }}Copy the code

Realize the principle of

After encapsulating SpringSecurity+JWT code into a generic module, it can be used by other modules that require login authentication. Let’s see how it is implemented. First, let’s take a look at the directory structure of Mall Security.

The directory structure

Mall ws-security ├ ─ ─ component | ├ ─ ─ JwtAuthenticationTokenFilterJWT logon authorization filter| ├ ─ ─ RestAuthenticationEntryPointUser-defined Result: No login or login expired| └ ─ ─ RestfulAccessDeniedHandlerCustom Result: No access permission├ ─ ─config| ├ ─ ─ IgnoreUrlsConfig-- Used to configure resource paths that do not require security protection| └ ─ ─ SecurityConfig-- SpringSecurity common configuration└ ─ ─ util └ ─ ─ JwtTokenUtil-- JWT token handling utility class
Copy the code

What changes have been made

I’ve actually added two classes, IgnoreUrlsConfig, to get unsecured resource paths from application.yml. A SecurityConfig extracts some common configuration for SpringSecurity.

  • IgnoreUrlsConfig:
/** * Created by macro on 2018/11/5. */
@Getter
@Setter
@ConfigurationProperties(prefix = "secure.ignored")
public class IgnoreUrlsConfig {

    private List<String> urls = new ArrayList<>();

}
Copy the code
  • The code in SecurityConfig:
/** * Created by macro on 2019/11/5. */ Created by macro on 2019/11/5
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = httpSecurity
                .authorizeRequests();
        // Access is allowed for resource paths that do not require protection
        for (String url : ignoreUrlsConfig().getUrls()) {
            registry.antMatchers(url).permitAll();
        }
        // OPTIONS requests that allow cross-domain requests
        registry.antMatchers(HttpMethod.OPTIONS)
                .permitAll();
        // Any request requires authentication
        registry.and()
                .authorizeRequests()
                .anyRequest()
                .authenticated()
                // Disable cross-site request protection and do not use session
                .and()
                .csrf()
                .disable()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                // Custom permission denial handling class
                .and()
                .exceptionHandling()
                .accessDeniedHandler(restfulAccessDeniedHandler())
                .authenticationEntryPoint(restAuthenticationEntryPoint())
                // Custom permission interceptor JWT filter
                .and()
                .addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService())
                .passwordEncoder(passwordEncoder());
    }

    @Bean
    public PasswordEncoder passwordEncoder(a) {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter(a) {
        return new JwtAuthenticationTokenFilter();
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean(a) throws Exception {
        return super.authenticationManagerBean();
    }

    @Bean
    public RestfulAccessDeniedHandler restfulAccessDeniedHandler(a) {
        return new RestfulAccessDeniedHandler();
    }

    @Bean
    public RestAuthenticationEntryPoint restAuthenticationEntryPoint(a) {
        return new RestAuthenticationEntryPoint();
    }

    @Bean
    public IgnoreUrlsConfig ignoreUrlsConfig(a) {
        return new IgnoreUrlsConfig();
    }

    @Bean
    public JwtTokenUtil jwtTokenUtil(a) {
        return newJwtTokenUtil(); }}Copy the code

Project source code address

Github.com/macrozheng/…

The public,

Mall project full set of learning tutorials serialized, attention to the public number the first time access.