• SpringBoot框架:集成Security完成认证鉴权


    一、导入依赖包

      1、导入security相关包:

    <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-security</artifactId>
    </dependency>

    二、基础部署

      1、HelloController.java:

      在Controller层里编写一些简单的接口,用于测试认证和鉴权。

    package com.example.demo.controller;
    
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class HelloController {
        @RequestMapping("/hello")
        public String hello(){
            return "hello";
        }
        
        @RequestMapping("/404")
        public String hello404(){
            return "404";
        }
        
        @RequestMapping("/403")
        public String hello403(){
            return "403";
        }
        
        @RequestMapping("/500")
        public String hello500(){
            return "500";
        }
    }

      2、UserPo.java:

      用户实体类,用来存储用户信息和用户所拥有的的角色权限。

    package com.example.demo.po;
    
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.authority.SimpleGrantedAuthority;
    import org.springframework.security.core.userdetails.UserDetails;
    
    import java.io.Serializable;
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.List;
    
    public class UserPo implements Serializable, UserDetails {
        /** 主键id */
        private Long id;
        /** 用户名 */
        private String userName;
        /** 密码 */
        private String password;
        /** 昵称 */
        private String nickName;
        /** 用户是否可用 */
        private boolean enabled;
        /** 角色集合 */
        private List<RolePo> roles;
        /** 注册时间 */
        private String regTime;
    
        public Long getId() {
            return id;
        }
    
        public void setId(Long id) {
            this.id = id;
        }
    
        @Override
        public String getUsername() {
            return userName;
        }
    
        /**
         * 获取角色权限
         * @return
         */
        @Override
        public Collection<? extends GrantedAuthority> getAuthorities() {
            List<GrantedAuthority> authorities = new ArrayList<>();
            for (RolePo role : roles) {
                authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getName()));
            }
            return authorities;
        }
    
    
        /**
         * 账户未使用
         * @return
         */
        @Override
        public boolean isAccountNonExpired() {
            return true;
        }
    
        /**
         * 账户未锁定
         * @return
         */
        @Override
        public boolean isAccountNonLocked() {
            return true;
        }
    
        /**
         * 权限未启用
         * @return
         */
        @Override
        public boolean isCredentialsNonExpired() {
            return true;
        }
    
        public String getUserName() {
            return userName;
        }
    
        public void setUserName(String userName) {
            this.userName = userName;
        }
    
        public String getNickName() {
            return nickName;
        }
    
        public void setNickName(String nickName) {
            this.nickName = nickName;
        }
    
        @Override
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
    
        @Override
        public boolean isEnabled() {
            return enabled;
        }
    
        public void setEnabled(boolean enabled) {
            this.enabled = enabled;
        }
    
        public List<RolePo> getRoles() {
            return roles;
        }
    
        public void setRoles(List<RolePo> roles) {
            this.roles = roles;
        }
    
        public String getRegTime() {
            return regTime;
        }
    
        public void setRegTime(String regTime) {
            this.regTime = regTime;
        }
    
    }

      该类实现UserDetails接口,这个是Sercurity里自带的类,而且实现其中的各个方法,像getAuthorities这个方法是比较重要的,要将自己从数据库里读出的用户角色进行处理,带上角色前缀“ROLE_”,用于鉴权的hasRole方法使用。

      类似于isAccountNonExpired、isAccountNonLocked、isCredentialsNonExpired这些方法,要返回true,否则在登录时会提示用户被锁住等信息。

      3、UserService.java:

      UserService直接继承UserDetailsService类,在实现类里对该类的方法进行重写。

    package com.example.demo.service;
    
    import org.springframework.security.core.userdetails.UserDetailsService;
    
    public interface UserService extends UserDetailsService {
    
    }

      4、UserServiceImpl.java:

      UserServiceImpl实现UserDetailsService中的loadUserByUsername

    package com.example.demo.service.impl;
    
    import com.example.demo.mapper.RoleMapper;
    import com.example.demo.mapper.UserMapper;
    import com.example.demo.po.RolePo;
    import com.example.demo.po.UserPo;
    import com.example.demo.service.UserService;
    import org.apache.commons.lang.StringUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.security.core.userdetails.UsernameNotFoundException;
    import org.springframework.stereotype.Service;
    import java.util.List;
    
    @Service
    public class UserServiceImpl implements UserService {
    
        @Autowired
        UserMapper userMapper;
        @Autowired
        RoleMapper roleMapper;
    
        /**
         * 根据用户名获取用户信息
         * @param s
         * @return
         * @throws UsernameNotFoundException
         */
        @Override
        public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
            //参数为空,返回空
            if(StringUtils.isEmpty(s)){
                return null;
            }
            //参数不为空,返回获取到的用户信息
            UserPo userPo = userMapper.getUserByUserName(s);
            //填充用户角色信息
            List<RolePo> rolePos = roleMapper.getRolesByUserId(userPo.getId());
            userPo.setRoles(rolePos);
            userPo.getAuthorities();
            return userPo;
        }
    }

      根据用户名获取用户信息,并通过用户与角色的关联关系取得角色信息,使用getAuthorities方法将角色配给用户。

      5、WebSecurityConfig.java:

      该类继承WebSecurityConfigurerAdapter适配器,添加加密工具以及配置相关接口的开放和拦截。

    package com.example.demo.config;
    
    import com.example.demo.service.UserService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    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.WebSecurityConfigurerAdapter;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;
    
    @Configuration
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Autowired
        UserService userService;
    
        /**
         * 获取加密工具
         * @return
         */
        @Bean
        public PasswordEncoder getPasswordEncoder(){
            return new BCryptPasswordEncoder();
        }
    
        @Override
        public void configure(AuthenticationManagerBuilder auth) throws Exception{
            auth.userDetailsService(userService)
                    .passwordEncoder(getPasswordEncoder());
        }
    
        /**
         * 处理接口的开放和拦截
         * @param http
         * @throws Exception
         */
        @Override
        protected void configure(HttpSecurity http) throws Exception{
            http.authorizeRequests()
                    //开放拦截
                    .antMatchers("/500").permitAll()
                    .antMatchers("/403").permitAll()
                    .antMatchers("/404").permitAll()
                    .antMatchers("/hello").hasRole("admin")
                    //其他任何请求都要进行身份认证
                    .anyRequest()
                    .authenticated()
                    .and()
                    //表单提交数据
                    .formLogin()
                    //配置登录接口
                    .loginProcessingUrl("/login")
                    .and()
                    //关闭跨站请求伪造保护
                    .csrf().disable();
        }
    }

      按照上面的配置,现在404、403、500接口都是开放的,认证之后即可访问,不做权限拦截。

      但是hello这个接口需要登录认证之后,再进行权限判断,即角色字段要与hasRole中的一致。

  • 相关阅读:
    ThinkPHP讲解(一)框架基础
    smarty简单介绍
    留言板
    文件系统处理
    文件上传(带有预览模式)
    文件上传(无预览模式版)
    注册、登陆、审核练习
    session讲解(二)——商城购物车练习
    session讲解(一)——登录网页练习
    P6216 回文匹配
  • 原文地址:https://www.cnblogs.com/guobin-/p/14207032.html
Copyright © 2020-2023  润新知