在上一篇Day 25 - Spring Security (二) UserDetailsService中有實作了UserDetailsService 進行基本的使用者資訊驗證,而實務上我們不會只簡單比對使用者名稱和密碼,還會檢查帳號狀態等資訊,因此我們這篇文章來實作自定義的AuthenticationProvider。
package com.example.iThomeIronMan.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import com.example.iThomeIronMan.security.CustomAuthenticationFailureHandler;
import com.example.iThomeIronMan.security.CustomAuthenticationProvider;
import com.example.iThomeIronMan.security.CustomAuthenticationSuccessHandler;
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomAuthenticationProvider authProvider;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// TODO Auto-generated method stub
auth.authenticationProvider(authProvider);
}
// 忽略...
}
package com.example.iThomeIronMan.service.impl;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.example.iThomeIronMan.dao.MemberAccountDao;
import com.example.iThomeIronMan.model.Member;
import com.example.iThomeIronMan.model.MemberAccount;
import com.example.iThomeIronMan.service.MemberAccountService;
import com.example.iThomeIronMan.service.MemberService;
import com.example.iThomeIronMan.service.ex.AccountDuplicateException;
import com.example.iThomeIronMan.service.ex.InsertException;
@Service
public class MemberAccountServiceImpl implements MemberAccountService, UserDetailsService {
// 忽略...
public MemberAccount login(MemberAccount memberAccount) {
// 檢查帳號是否存在
MemberAccount data = memberAccountDao.getMemberAccountByAccount(memberAccount.getAccount());
if(data == null) {
return null;
}
// 比對密碼
if(!passwordEncoder.matches(memberAccount.getPassword() + data.getSalt(), data.getPassword())) return null;
return data;
}
}
package com.example.iThomeIronMan.security;
import java.util.Collection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Component;
import com.example.iThomeIronMan.model.MemberAccount;
import com.example.iThomeIronMan.service.MemberAccountService;
@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
@Autowired
private MemberAccountService memberAccountService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// TODO Auto-generated method stub
String account = authentication.getName();
String password = String.valueOf(authentication.getCredentials());
try {
MemberAccount memberAccount = new MemberAccount();
memberAccount.setAccount(account);
memberAccount.setPassword(password);
memberAccount = memberAccountService.login(memberAccount);
Collection<? extends GrantedAuthority> authorities = memberAccount.getAuthorities();
return new UsernamePasswordAuthenticationToken(memberAccount, password, authorities);
}
catch(Exception e) {
e.printStackTrace();
return null;
}
}
@Override
public boolean supports(Class<?> authentication) {
// TODO Auto-generated method stub
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}