SpringBoot實戰電商項目mall(25k+star)地址:github.com/macrozheng/…css
學習過個人mall項目的應該知道,mall-admin
模塊是使用SpringSecurity+JWT來實現登陸認證的,而mall-portal
模塊是使用的SpringSecurity基於Session的默認機制來實現登錄認證的。不少小夥伴都找不到mall-portal
的登陸接口,最近我把這兩個模塊的登陸認證給統一了,都使用SpringSecurity+JWT的形式實現。 主要是經過把登陸認證的通用邏輯抽取到了mall-security
模塊來實現的,下面咱們講講如何使用mall-security
模塊來實現登陸認證,僅需四步便可。html
這裏咱們以
mall-portal
改造爲例來講說如何實現。java
mall-security
依賴:<dependency>
<groupId>com.macro.mall</groupId>
<artifactId>mall-security</artifactId>
</dependency>
複製代碼
mall-security
中的SecurityConfig配置,而且配置一個UserDetailsService接口的實現類,用於獲取登陸用戶詳情:/** * mall-security模塊相關配置 * 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() {
//獲取登陸用戶信息
return username -> memberService.loadUserByUsername(username);
}
}
複製代碼
secure:
ignored:
urls: #安全路徑白名單
- /swagger-ui.html
- /swagger-resources/**
- /swagger/**
- /**/v2/api-docs
- /**/*.js
- /**/*.css
- /**/*.png
- /**/*.ico
- /webjars/springfox-swagger-ui/**
- /druid/**
- /actuator/**
- /sso/**
- /home/**
複製代碼
/** * 會員登陸註冊管理Controller * Created by macro on 2018/8/3. */
@Controller
@Api(tags = "UmsMemberController", description = "會員登陸註冊管理")
@RequestMapping("/sso")
public class UmsMemberController {
@Value("${jwt.tokenHeader}")
private String tokenHeader;
@Value("${jwt.tokenHead}")
private String tokenHead;
@Autowired
private UmsMemberService memberService;
@ApiOperation("會員登陸")
@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("用戶名或密碼錯誤");
}
Map<String, String> tokenMap = new HashMap<>();
tokenMap.put("token", token);
tokenMap.put("tokenHead", tokenHead);
return CommonResult.success(tokenMap);
}
@ApiOperation(value = "刷新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已通過期!");
}
Map<String, String> tokenMap = new HashMap<>();
tokenMap.put("token", refreshToken);
tokenMap.put("tokenHead", tokenHead);
return CommonResult.success(tokenMap);
}
}
複製代碼
將SpringSecurity+JWT的代碼封裝成通用模塊後,就能夠方便其餘須要登陸認證的模塊來使用,下面咱們來看看它是如何實現的,首先咱們看下
mall-security
的目錄結構。git
mall-security
├── component
| ├── JwtAuthenticationTokenFilter -- JWT登陸受權過濾器
| ├── RestAuthenticationEntryPoint -- 自定義返回結果:未登陸或登陸過時
| └── RestfulAccessDeniedHandler -- 自定義返回結果:沒有權限訪問時
├── config
| ├── IgnoreUrlsConfig -- 用於配置不須要安全保護的資源路徑
| └── SecurityConfig -- SpringSecurity通用配置
└── util
└── JwtTokenUtil -- JWT的token處理工具類
複製代碼
其實我也就添加了兩個類,一個IgnoreUrlsConfig,用於從application.yml中獲取不須要安全保護的資源路徑。一個SecurityConfig提取了一些SpringSecurity的通用配置。github
/** * 用於配置不須要保護的資源路徑 * Created by macro on 2018/11/5. */
@Getter
@Setter
@ConfigurationProperties(prefix = "secure.ignored")
public class IgnoreUrlsConfig {
private List<String> urls = new ArrayList<>();
}
複製代碼
/** * 對SpringSecurity的配置的擴展,支持自定義白名單資源路徑和查詢用戶邏輯 * 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();
//不須要保護的資源路徑容許訪問
for (String url : ignoreUrlsConfig().getUrls()) {
registry.antMatchers(url).permitAll();
}
//容許跨域請求的OPTIONS請求
registry.antMatchers(HttpMethod.OPTIONS)
.permitAll();
// 任何請求須要身份認證
registry.and()
.authorizeRequests()
.anyRequest()
.authenticated()
// 關閉跨站請求防禦及不使用session
.and()
.csrf()
.disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
// 自定義權限拒絕處理類
.and()
.exceptionHandling()
.accessDeniedHandler(restfulAccessDeniedHandler())
.authenticationEntryPoint(restAuthenticationEntryPoint())
// 自定義權限攔截器JWT過濾器
.and()
.addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService())
.passwordEncoder(passwordEncoder());
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter() {
return new JwtAuthenticationTokenFilter();
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public RestfulAccessDeniedHandler restfulAccessDeniedHandler() {
return new RestfulAccessDeniedHandler();
}
@Bean
public RestAuthenticationEntryPoint restAuthenticationEntryPoint() {
return new RestAuthenticationEntryPoint();
}
@Bean
public IgnoreUrlsConfig ignoreUrlsConfig() {
return new IgnoreUrlsConfig();
}
@Bean
public JwtTokenUtil jwtTokenUtil() {
return new JwtTokenUtil();
}
}
複製代碼
mall項目全套學習教程連載中,關注公衆號第一時間獲取。spring