Day 26 - Spring Security (三) DaoAuthenticationProvider

在上一篇Day 25 - Spring Security (二) UserDetailsService中有实作了UserDetailsService 进行基本的使用者资讯验证,而实务上我们不会只简单比对使用者名称和密码,还会检查帐号状态等资讯,因此我们这篇文章来实作自定义的AuthenticationProvider。

实作

调整SecurityConfig

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);
	}

	// 忽略...

}

调整MemberAccountService

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;
	}

}

建立CustomAuthenticationProvider

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);
	}

}

<<:  EP 26 - [Ruby on Rails] 使用状态机管理订单

>>:  JavaScript内建标准物件:日期

Day 19:专案管理

前言 专案管理是一门很深的学问,也不只是软件业,各行各业都有,最早是来自土木建筑、国防领域。 牵扯到...

12. STM32-CANBus概念介绍

CAN Protocol 介绍 CAN 全名为控制器区域网路 (Controller Area Ne...

第21天 - 来试着做一个简易购物系统(5),统计购物车价格

延续昨天的构想,今天来试试看能否成功。 昨天的构想好像有点错误,因为购物车只会有1台,且纪录是暂时的...

LiteX/VexRiscv 简介与使用 (二点七五) 斯有海与陆地植物

有点惨,上篇说得想办法把FPU塞进来的路给打通,但是实在受限硬体资源,有点悲剧。 我是已经订了一张8...

Day 12 | 元件状态:读取 Loading States

在 Livewire 上的操作都会透过 AJAX 将资料往返与前後端之间,有些较长的请求可能不会即时...