springboot2セキュリティ-oauth2は認証サーバーを構築し、ユーザーパスワードの暗号化を変更し、ユーザー権限認証を変更します

1.認証サーバーを構築します

新しいspringboot2プロジェクトを作成し、次の2つの構成クラスを追加してサーバーを起動します

1. AuthorizationServerConfiguration

主に3つの構成方法があります

(1)ここでは、2つのAPIのアクセス制限を解除し、クライアントのIDとパスワードをフォームフォームに直接書き込むことができるようにします。

-クライアントはユーザーではなく、サードパーティのWebサイトを参照しています。クライアントを使用してコードでクライアントを表す

 

(2)2番目の方法は、クライアントの情報を指定するために使用されます

 

(3)3番目の方法は、トークンの保存場所を構成するために使用されます

 

2. WebSecurityConfiguration

主に3つの豆を提供するために使用されます

 

 

これで、次の2つのAPIを使用してテストします

(1)http:// localhost:37001 / oauth / token

(2)http:// localhost:37001 / oauth / check_token

(コード)Lanzous Cloud:https://wws.lanzous.com/iG4xHlo426h

 

 

変更できる場所がいくつかあります

(データベース)Lanzous Cloud:https://wws.lanzous.com/ibQBPlo420b

(1)クライアント情報はデータベースに保存されます

(2)トークンはredisに保存されます

(3)ユーザー情報はデータベースに保存されます

ユーザー名を入力して、UserDetailsインターフェースの実装クラスに戻ります

 

 

 

2つ目は、ユーザーパスワードの暗号化を変更する

(1)1つの方法は、カスタムPasswordEncoderを使用することです

(2)別の方法は、ユーザーログイン認証のロジックをオーバーライドすることです

 ここにソルト暗号化を追加するには、md5を使用します

package hlmio.oauth2.conf.security.login;

import hlmio.oauth2.model.User;
import lombok.extern.java.Log;
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.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;


/**
 * 登录认证的Provider,自定义实现{@link AuthenticationProvider} <br>
 */
@Log
@Component
public class LoginAuthenticationProvider implements AuthenticationProvider {

    @Autowired
    private UserDetailsService userDetailsServiceImpl;
    @Autowired
    private PasswordEncoder passwordEncoder;


    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {

        // http请求的账户密码
        String username = authentication.getName();
        String password = (String) authentication.getCredentials();

        // 根据用户名查询数据库
        UserDetails userDetails = userDetailsServiceImpl.loadUserByUsername(username);

        log.info(String.format("[http请求的账户密码]: %s/%s", username, password));

        if (userDetails == null) {
            throw new BadCredentialsException("用户名未找到");
        }

        String rawPassword = password + ((User)userDetails).getSalt();
        String encodedPassword = "{MD5}"+userDetails.getPassword();
        if(!passwordEncoder.matches(rawPassword,encodedPassword)){
            throw new BadCredentialsException("密码不正确");
        }

        return new UsernamePasswordAuthenticationToken(userDetails, password, userDetails.getAuthorities());
    }

    /**
     * 是否支持处理当前Authentication对象类型
     */
    @Override
    public boolean supports(Class<?> authentication) {
        return true;
    }
}

 

 

 

3、ユーザー権限認証を変更します

主にaccessDecisionManagerの権限判断ロジックを書き直すため

 

(1)MethodSecurityMetadataSourceは、メソッドアノテーションに書き込まれたパーミッション名を読み取るために使用されます

package hlmio.oauth2.conf.security.access;

import hlmio.oauth2.conf.security.other.NoAccess;
import hlmio.oauth2.conf.security.other.NoAuth;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.method.AbstractMethodSecurityMetadataSource;
import org.springframework.stereotype.Component;
import org.springframework.util.ClassUtils;


import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;


@Component
public class MyMethodSecurityMetadataSource extends AbstractMethodSecurityMetadataSource {

    public Collection<ConfigAttribute> getAttributes(Method method, Class<?> targetClass) {

        if (method.getDeclaringClass() == Object.class) {
            return Collections.emptyList();
        }
        if(targetClass.getName().indexOf("hlmio.oauth2.api") == -1){
            return Collections.emptyList();
        }

        System.out.println("method: '" + method.getName() + "'     class: '" + targetClass + "'");

        ArrayList<ConfigAttribute> attrs = new ArrayList(5);

        // region 权限(1):控制器名::方法名
        // 获取控制器的名称
        String controllerName_all = targetClass.getName();
        String[] controllerName_arr = controllerName_all.split("\\.");
        String controllerName = controllerName_arr[controllerName_arr.length-1];
        // 获取方法名
        String funcName = method.getName();
        // 权限字段的名称
        String permName = controllerName + "::" + funcName;
        System.out.println(permName);
        attrs.add(new MyConfigAttribute(permName));
        // endregion

        // region 权限(2):注解NoAuth
        NoAuth noAuth = (NoAuth)this.findAnnotation(method, targetClass, NoAuth.class);
        NoAccess noAccess = (NoAccess)this.findAnnotation(method, targetClass, NoAccess.class);
        if(noAuth!=null){
            attrs.add(new MyConfigAttribute("NoAuth"));
        }
        if(noAccess!=null){
            attrs.add(new MyConfigAttribute("NoAccess"));
        }
        // endregion


        attrs.trimToSize();
        return attrs;
    }

    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

    private <A extends Annotation> A findAnnotation(Method method, Class<?> targetClass, Class<A> annotationClass) {
        Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
        A annotation = AnnotationUtils.findAnnotation(specificMethod, annotationClass);
        if (annotation != null) {
            this.logger.debug(annotation + " found on specific method: " + specificMethod);
            return annotation;
        } else {
            if (specificMethod != method) {
                annotation = AnnotationUtils.findAnnotation(method, annotationClass);
                if (annotation != null) {
                    this.logger.debug(annotation + " found on: " + method);
                    return annotation;
                }
            }

            annotation = AnnotationUtils.findAnnotation(specificMethod.getDeclaringClass(), annotationClass);
            if (annotation != null) {
                this.logger.debug(annotation + " found on: " + specificMethod.getDeclaringClass().getName());
                return annotation;
            } else {
                return null;
            }
        }
    }
}

フレームワークに必要なパーミッションアイテムクラス

package hlmio.oauth2.conf.security.access;

import lombok.Setter;
import org.springframework.security.access.ConfigAttribute;

public class MyConfigAttribute implements ConfigAttribute {

    @Setter
    String attribute;

    MyConfigAttribute(){
    }

    MyConfigAttribute(String attribute){
        this.attribute = attribute;
    }

    @Override
    public String getAttribute(){
        return attribute;
    }
}

 

(2)AccessDecisionManagerで許可判断を書き込むロジック

package hlmio.oauth2.conf.security.access;

import org.aopalliance.intercept.MethodInvocation;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;


@Component
public class MyAccessDecisionManager implements AccessDecisionManager {

    public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {

        List<String> targetAccessList =  configAttributes.stream()
                                    .map( i -> i.getAttribute())
                                    .collect(Collectors.toList());
        // 放行无需登录和权限的注解
        if(targetAccessList.contains("NoAuth")){
            return;
        }
        // 拒绝未登录用户
        if (authentication == null || "anonymousUser".equals(authentication.getName())) {
            throw new AccessDeniedException("当前访问需要登录");
        }
        // 放行无需权限的注解
        if(targetAccessList.contains("NoAccess")){
            return;
        }

        List<String> userAccessList =  authentication.getAuthorities().stream()
                                            .map( i -> i.getAuthority())
                                            .collect(Collectors.toList());

        for (String s : userAccessList) {
            for (String s1 : targetAccessList) {
                if(s != null){
                    if(s.equals(s1)){
                        return;
                    }
                }
            }
        }


        throw new AccessDeniedException("当前访问没有权限");
    }

    public boolean supports(ConfigAttribute attribute) {
        return true;
    }

    public boolean supports(Class<?> clazz) {
        return MethodInvocation.class.isAssignableFrom(clazz);
    }
}

 

github:https//github.com/hl-mio/a1

おすすめ

転載: blog.csdn.net/u013595395/article/details/113810337