Home  >  Article  >  Java  >  How does SpringBoot integrate SpringSecurityOauth2 to implement dynamic permission issues for authentication?

How does SpringBoot integrate SpringSecurityOauth2 to implement dynamic permission issues for authentication?

王林
王林forward
2023-05-11 10:28:051398browse

Preparation

spring-boot: 2.1.4.RELEASE

spring-security-oauth3: 2.3.3.RELEASE (If you want to use the source code, do not change this version number at will, because The writing method from 2.4 up is different)

mysql: 5.7

Effect display

Only postman is used for testing here, and the front-end page is not used for docking yet. Next There will be a page display for the permission allocation of the version role menu

1. Access the open interface http://localhost:7000/open/hello

How does SpringBoot integrate SpringSecurityOauth2 to implement dynamic permission issues for authentication?

2 . Access the protected interface http://localhost:7000/admin/user/info

How does SpringBoot integrate SpringSecurityOauth2 to implement dynamic permission issues for authentication?

## without a token. 3. Obtain the token after logging in, bring the token to access, and return successfully. The current login user information

How does SpringBoot integrate SpringSecurityOauth2 to implement dynamic permission issues for authentication?

How does SpringBoot integrate SpringSecurityOauth2 to implement dynamic permission issues for authentication?

realize

oauth3 has four modes in total, which will not be explained here. Yes, I searched online and found the same thing

Because now we only consider unilateral applications, we use the password mode.

There will be an article on SpringCloud Oauth3 later, gateway authentication

Let’s talk about a few points

1. Interceptor configuration dynamic permissions

How does SpringBoot integrate SpringSecurityOauth2 to implement dynamic permission issues for authentication?

Create a new MySecurityFilter class, inherit AbstractSecurityInterceptor, and implement the Filter interface

Initialization, custom access decision manager

@PostConstruct
 public void init(){
        super.setAuthenticationManager(authenticationManager);
        super.setAccessDecisionManager(myAccessDecisionManager);
  }

Custom filter calls security metadata Source

@Override
public SecurityMetadataSource obtainSecurityMetadataSource() {
    return this.mySecurityMetadataSource;
}

Let’s first look at the core code of the custom filter calling the secure metadata source

The following code is used to obtain the permissions (roles) required for the current request to come in

/**
     * 获得当前请求所需要的角色
     * @param object
     * @return
     * @throws IllegalArgumentException
     */
    @Override
    public Collection getAttributes(Object object) throws IllegalArgumentException {
        String requestUrl = ((FilterInvocation) object).getRequestUrl();

        if (IS_CHANGE_SECURITY) {
            loadResourceDefine();
        }
        if (requestUrl.indexOf("?") > -1) {
            requestUrl = requestUrl.substring(0, requestUrl.indexOf("?"));
        }
        UrlPathMatcher matcher = new UrlPathMatcher();
        List list = new ArrayList<>();  //无需权限的,直接返回
        list.add("/oauth/**");
        list.add("/open/**");
        if(matcher.pathsMatchesUrl(list,requestUrl))
            return null;

        Set roleNames = new HashSet();
        for (Resc resc: resources) {
            String rescUrl = resc.getResc_url();
            if (matcher.pathMatchesUrl(rescUrl, requestUrl)) {
                if(resc.getParent_resc_id() != null && resc.getParent_resc_id().intValue() == 1){   //默认权限的则只要登录了,无需权限匹配都可访问
                    roleNames = new HashSet();
                    break;
                }
                Map map = new HashMap();
                map.put("resc_id", resc.getResc_id());
                // 获取能访问该资源的所有权限(角色)
                List roles = roleRescMapper.findAll(map);
                for (RoleRescDTO rr : roles)
                    roleNames.add(rr.getRole_name());
            }
        }

        Set configAttributes = new HashSet();
        for(String roleName:roleNames)
            configAttributes.add(new SecurityConfig(roleName));

        log.debug("【所需的权限(角色)】:" + configAttributes);

        return configAttributes;
    }

Let’s take a look at the core code of the custom access decision manager. This code is mainly used to determine whether the currently logged in user (the role owned by the currently logged in user will be written in the last item) has the permission role

@Override
    public void decide(Authentication authentication, Object o, Collection configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
        if(configAttributes == null){   //属于白名单的,不需要权限
            return;
        }
        Iterator iterator = configAttributes.iterator();
        while (iterator.hasNext()){
            ConfigAttribute configAttribute = iterator.next();
            String needPermission = configAttribute.getAttribute();
            for (GrantedAuthority ga: authentication.getAuthorities()) {
                if(needPermission.equals(ga.getAuthority())){   //有权限,可访问
                    return;
                }
            }
        }
        throw new AccessDeniedException("没有权限访问");

    }

2. Customize authentication exceptions to return common results

Why is this needed? If this is not configured, it will be difficult for the front end and the back end to understand the content returned by the authentication failure. It is not possible yet. Unified interpretation, without further ado, let’s first look at the return situation without configuration and configuration

(1) Before customization, when accessing the protected API interface without a token, the returned result is as follows ’s

How does SpringBoot integrate SpringSecurityOauth2 to implement dynamic permission issues for authentication?

# (2) Let’s stipulate that after the interface that fails to authenticate returns to the interface, it will become the following. Is it better for us to process and prompt the user

How does SpringBoot integrate SpringSecurityOauth2 to implement dynamic permission issues for authentication?

Okay, let’s take a look at where to configure it

Our resource server OautyResourceConfig, rewrite the following part of the code to customize the authentication The result returned by the exception

You can refer to this https://www.yisu.com/article/131668.htm

@Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.authenticationEntryPoint(authenticationEntryPoint)    //token失效或没携带token时
                .accessDeniedHandler(requestAccessDeniedHandler);   //权限不足时
    }

How does SpringBoot integrate SpringSecurityOauth2 to implement dynamic permission issues for authentication?

3. Get the current Login user

First method: Use JWT to carry user information, and then parse after getting the token

No explanation for now

Second method: Write a SecurityUser to implement the UserDetails interface (This is the one used in this project)

The original only UserDetails interface only has username and password. Here we add the User in our system

protected User user;
    public SecurityUser(User user) {
        this.user = user;
    }

    public User getUser() {
        return user;
    }

In BaseController, each Controller will Inheriting this, we write the getUser() method in it. As long as the user brings a token to access, we can directly obtain the information of the currently logged in user.

protected User getUser() {
        try {
            SecurityUser userDetails = (SecurityUser) SecurityContextHolder.getContext().getAuthentication()
                    .getPrincipal();

            User user = userDetails.getUser();
            log.debug("【用户:】:" + user);

            return user;
        } catch (Exception e) {
        }
        return null;
    }

So after the user logs in successfully, how to get the user The role collection, etc., here we need to implement the UserDetailsService interface

How does SpringBoot integrate SpringSecurityOauth2 to implement dynamic permission issues for authentication?

@Service
public class TokenUserDetailsService implements UserDetailsService{

    @Autowired
    private LoginService loginService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = loginService.loadUserByUsername(username);  //这个我们拎出来处理
        if(Objects.isNull(user))
            throw new UsernameNotFoundException("用户名不存在");
        return new SecurityUser(user);
    }
}

Then set the UserDetailsService in our security configuration class to the one we wrote above

How does SpringBoot integrate SpringSecurityOauth2 to implement dynamic permission issues for authentication?

@Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

Finally we only need to implement our method in loginService, and judge whether the user exists based on our actual business processing, etc.

@Override
    public User loadUserByUsername(String username){
        log.debug(username);
        Map map = new HashMap();
        map.put("username",username);
        map.put("is_deleted",-1);
        User user = userMapper.findByUsername(map);
        if(user != null){
            map = new HashMap();
            map.put("user_id",user.getUser_id());
            //查询用户的角色
            List userRoles = userRoleMapper.findAll(map);
            user.setRoles(listRoles(userRoles));
            //权限集合
            Collection authorities = merge(userRoles);
            user.setAuthorities(authorities);
            return user;
        }
        return null;

    }

The database file is in this

How does SpringBoot integrate SpringSecurityOauth2 to implement dynamic permission issues for authentication?

The above is the detailed content of How does SpringBoot integrate SpringSecurityOauth2 to implement dynamic permission issues for authentication?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:yisu.com. If there is any infringement, please contact admin@php.cn delete