1. 程式人生 > >spring Security4 和 oauth2整合 註解+xml混合使用(替換使用者名稱密碼認證)

spring Security4 和 oauth2整合 註解+xml混合使用(替換使用者名稱密碼認證)

spring Security4 和 oauth2整合 (替換使用者名稱密碼認證)

之前已經寫了註解和xml配合搭建基本認證、頁面認證、授權碼認證、替換6位授權碼方法等,這次在前面的基礎上介紹如何替換使用者名稱密碼認證,下一篇介紹如何增加驗證碼等額外引數驗證方法。
程式碼比較多,這次只貼出來部分,完整程式碼在
git地址:https://gitee.com/xiaoyaofeiyang/OauthUmp

spring Security4 和 oauth2整合 註解+xml混合使用(基礎執行篇)
spring Security4 和 oauth2整合 註解+xml混合使用(進階篇)


spring Security4 和 oauth2整合 註解+xml混合使用(授權碼篇)
spring Security4 和 oauth2整合 註解+xml混合使用(注意事項篇)
spring Security4 和 oauth2整合 註解+xml混合使用(替換6位的授權碼)
spring Security4 和 oauth2整合 註解+xml混合使用(替換使用者名稱密碼認證)
spring Security4 和 oauth2整合 註解+xml混合使用(驗證碼等額外資料驗證)

使用者名稱密碼來源

首先,我們假設使用者名稱密碼是通過service層獲取的。這個邏輯就可以按照自己的邏輯去寫了。

1.實體

package com.ump.domain;

import java.util.UUID;

public class AppUser {
    private String uuid;
    private String userName;
    private String password;
    private String userType;
    public AppUser() {

    }

    public AppUser(String userName, String password) {
        this.userName = userName;
        this
.password = password; this.uuid = UUID.randomUUID().toString(); this.userType = "1"; } public AppUser(AppUser appUser) { this.userName = appUser.userName; this.password = appUser.password; this.uuid = appUser.uuid; this.userType = appUser.userType; } public String getUuid() { return uuid; } public void setUuid(String uuid) { this.uuid = uuid; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getUserType() { return userType; } public void setUserType(String userType) { this.userType = userType; } }

2.service服務

package com.ump.service;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import org.springframework.stereotype.Service;

import com.ump.domain.AppUser;

@Service
public class AppUserService {

    public AppUser findByName(String userName) {
        Map<String,AppUser> users = new HashMap<String,AppUser>();
        AppUser user1 = new AppUser();
        user1.setUserName("bill");
        user1.setPassword("abc123");
        user1.setUserType("1");
        user1.setUuid(UUID.randomUUID().toString());
        users.put("bill", user1);

        AppUser user2 = new AppUser();
        user2.setUserName("bob");
        user2.setPassword("abc123");
        user2.setUserType("1");
        user2.setUuid(UUID.randomUUID().toString());
        users.put("bob", user2);
        return users.get(userName);
    }

}

替換UserDetails

使用者來源不是直接指定了,而是從service層取了,所以我們要自定義UserDetails

package com.ump.oauth.detail;

import java.util.Collection;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;

import com.ump.domain.AppUser;

public class OauthUserDetails extends AppUser implements UserDetails{

    public OauthUserDetails(AppUser appUser) {
        super(appUser);
    }

    /**
     * 
     */
    private static final long serialVersionUID = 6272869114201567325L;

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return AuthorityUtils.createAuthorityList("USER");
    }

    @Override
    public String getUserType() {
        return super.getUserType();
    }

    @Override
    public String getUsername() {
        return super.getUserName();
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }

}

自定義UserDetailsService

我們需要提供loadUserByUsername方法。

package com.ump.oauth.part;

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.stereotype.Service;

import com.ump.domain.AppUser;
import com.ump.oauth.detail.OauthUserDetails;
import com.ump.service.AppUserService;

@Service("oauthUserDetailsService")
public class OauthUserDetailsService implements UserDetailsService {
    @Autowired
    private AppUserService appUserService;

    @Override
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
        AppUser user;
        try {
            user = appUserService.findByName(userName);
        } catch (Exception e) {
            throw new UsernameNotFoundException("user select fail");
        }
        if(user == null){
            throw new UsernameNotFoundException("no user found");
        } else {
            try {
                return new OauthUserDetails(user);
            } catch (Exception e) {
                throw new UsernameNotFoundException("user role select fail");
            }
        }
    }

}

AuthenticationProvider

AuthenticationProvider提供認證邏輯。

package com.ump.oauth.part;

import java.util.Collection;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
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.ump.oauth.detail.OauthAddUserDetails;
import com.ump.oauth.detail.OauthUserDetails;

@Component
public class OauthAuthenticationProvider implements AuthenticationProvider {
    @Autowired
    private OauthUserDetailsService oauthUserDetailsService;

    /**
     * 自定義驗證方式
     */
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        //驗證碼等校驗
//      OauthAddUserDetails details = (OauthAddUserDetails) authentication.getDetails();
//
//      System.out.println(details.getToken() + "+++++++++++++++++" + details.getSessionToken());
//      if (!details.getToken().equalsIgnoreCase(details.getSessionToken())) {
//          throw new BadCredentialsException("驗證碼錯誤。");
//      }

        //使用者名稱密碼校驗
        OauthUserDetails oauthUserDetails = (OauthUserDetails) oauthUserDetailsService
                .loadUserByUsername(authentication.getName());
        System.out.println(authentication.getName() + "+++++++++++++++++" + authentication.getCredentials());
        if (!oauthUserDetails.getUserName().equals(authentication.getName())
                || !oauthUserDetails.getPassword().equals(authentication.getCredentials())) {
            throw new BadCredentialsException("使用者名稱或密碼錯誤。");
        }
        Collection<? extends GrantedAuthority> authorities = oauthUserDetails.getAuthorities();
        return new UsernamePasswordAuthenticationToken(oauthUserDetails.getUsername(), oauthUserDetails.getPassword(),
                authorities);
    }

    @Override
    public boolean supports(Class<?> arg0) {
        return true;
    }
}

spring security配置

繼承WebSecurityConfigurerAdapter的OAuth2SecurityConfiguration需要指向AuthenticationProvider。

package com.ump.oauth.config;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.authentication.AuthenticationManager;
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.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.approval.ApprovalStore;
import org.springframework.security.oauth2.provider.approval.TokenApprovalStore;
import org.springframework.security.oauth2.provider.approval.TokenStoreUserApprovalHandler;
import org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint;
import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.WebAuthenticationDetails;

import com.ump.oauth.part.OauthAuthenticationProvider;

@Configuration
@EnableWebSecurity
public class OAuth2SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    @Qualifier("myClientDetailsService")
    private ClientDetailsService clientDetailsService;

//  @Autowired
//  @Qualifier("myUserDetailsService")
//  private UserDetailsService userDetailsService;

//  @Autowired
//    public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
//      //auth.userDetailsService(userDetailsService);
//      auth.inMemoryAuthentication()
//        .withUser("bill").password("abc123").roles("ADMIN").and()
//        .withUser("bob").password("abc123").roles("USER");
//    }

    @Autowired
    private OauthAuthenticationProvider oauthAuthenticationProvider; 

    @Autowired
    @Qualifier("oauthAuthenticationDetailsSource")
    private AuthenticationDetailsSource<HttpServletRequest, WebAuthenticationDetails> authenticationDetailsSource;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(oauthAuthenticationProvider);
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        SimpleUrlAuthenticationFailureHandler hander = new SimpleUrlAuthenticationFailureHandler();
        hander.setUseForward(true);
        hander.setDefaultFailureUrl("/authlogin.jsp");

        http
        .csrf().disable()
        .authorizeRequests()
        .antMatchers("/oauth/token")
        .permitAll().and()
        .formLogin().loginPage("/authlogin.jsp")
        .usernameParameter("userName").passwordParameter("userPwd")
        .authenticationDetailsSource(authenticationDetailsSource)
//      .loginProcessingUrl("/login").failureUrl("/index1.jsp")
        .loginProcessingUrl("/login").failureHandler(hander)
        .and().logout().logoutUrl("/logout");
        http.authorizeRequests().antMatchers("/user/**").authenticated();
    }

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

    @Bean
    @Autowired
    public TokenStoreUserApprovalHandler userApprovalHandler(TokenStore tokenStore){
        TokenStoreUserApprovalHandler handler = new TokenStoreUserApprovalHandler();
        handler.setTokenStore(tokenStore);
        handler.setRequestFactory(new DefaultOAuth2RequestFactory(clientDetailsService));
        handler.setClientDetailsService(clientDetailsService);
        return handler;
    }

    @Bean
    @Autowired
    public ApprovalStore approvalStore(TokenStore tokenStore) throws Exception {
        TokenApprovalStore store = new TokenApprovalStore();
        store.setTokenStore(tokenStore);
        return store;
    }

}

這樣就可以了,中間有其他程式碼,刪減即可,增加驗證碼的邏輯單獨分開了,方便擴充套件。下一篇說明。