spring boot Security Oauth2.0简单集成


pom文件

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

        <dependency>
            <groupId>org.springframework.security.oauth</groupId>
            <artifactId>spring-security-oauth2</artifactId>
            <version>2.3.3.RELEASE</version>
        </dependency>

        <!--web依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

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

用户实体 为了方便操作,给用户赋权限(上篇使用了Security 的 USER对象,这次换个方式耍耍吧)

/**
 * @Title: LoginAppUser
 * @description: 用户信息管理
 * @author: LIUFANG
 * @create: 2020/3/13 12:54
 * @Version: v1.0
 */
@Getter
@Setter
public class LoginAppUser implements UserDetails {

    private Long id;
    private String username;
    private String password;
    private String nickname;
    private String headImgUrl;
    private String phone;
    private Integer sex;
    /**
     * 状态
     */
    private Boolean enabled;
    private String type;
    private String deptId;
    private String deptName;
    private Date createTime;
    private Date updateTime;

    private Set<String> sysRoles;

    private Set<String> permissions;
	/**权限的操作直接放在此处了,简单粗暴,如果你开心,你可以把类做的细化一点*/
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        Collection<GrantedAuthority> collection = new HashSet<>();
        /**为什么加ROLE_,看了一下源码,你可以理解为:区分资源和权限的标识符*/
        collection.add(new SimpleGrantedAuthority("ROLE_"+"USER"));
        return collection;
    }

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

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

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

    @Override
    public boolean isEnabled() {
        return true;
    }
    @Override
    public String getUsername() {
        /**写死的数据,真实开发查询数据库就OK了*/
        return "user";
    }

UserDetailsService

/**
 * @Title: MyUserDetailsService
 * @description: 用户管理
 * @author: LIUFANG
 * @create: 2020/3/13 9:27
 * @Version: v1.0
 */
@Component
public class MyUserDetailsService implements UserDetailsService {

    @Autowired
    private PasswordEncoder userPasswordEncoder;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        LoginAppUser loginAppUser = new LoginAppUser();
        loginAppUser.setUsername("user");
        loginAppUser.setPassword(userPasswordEncoder.encode("123456"));
        return loginAppUser;
    }
}

WebSecurityConfig

/**
 * @Title: SecurityConfig
 * @description: 权限配置
 * @author: LIUFANG
 * @create: 2020/3/13 9:12
 * @Version: v1.0
 */
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
@Configuration
@Order(2)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyUserDetailsService userDetailsService;

    /**
     * 一定要将 userDetailsService 设置到 AuthenticationManagerBuilder 中
     * 不然后面校验ClientDetailsService时会找不到UsernamePasswordToken的Provider
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(userPasswordEncoder());
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
       http.csrf().disable();
        http.requestMatchers().antMatchers("/oauth/**","/login/**","/logout/**")
            .and()
            .authorizeRequests()
            .antMatchers("/oauth/**").authenticated()
            .and()
            .formLogin().permitAll(); //新增login form支持用户登录及授权
    }

    @Bean
    public PasswordEncoder userPasswordEncoder(){
        return new BCryptPasswordEncoder();
    }


    /**
     * 覆盖WebSecurityConfigurerAdapter类(本类集成的爸爸)authenticationManagerBean的方法,最终要的一点,重写的时候,直接使用super就OK,这波操作给6分
     * 注意的是,这个bean不重写,在OauthAuthorizationServerConfig是无法获取的,这个是个小坑
     * @return
     * @throws Exception
     */
    @Bean
    @Override
    protected AuthenticationManager authenticationManager() throws Exception{
        return super.authenticationManager();
    }

Oauth 配置类

/**
 * @Title: OauthAuthorizationServerConfig
 * @description: Oauth2.0配置
 * @author: LIUFANG
 * @create: 2020/3/13 10:22
 * @Version: v1.0
 */
@Configuration
@EnableAuthorizationServer
public class OauthAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    /**这个地方需要注意一下,这个bean必须自行创建出来,参照WebSecurityConfig类*/
    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private MyUserDetailsService userDetailsService;

    /**
     * 配置访问端点和令牌服务
     * @param security
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        /**注意这个allowFormAuthenticationForClients,开启表单验证*/
        security
                .tokenKeyAccess("permitAll()")
                .checkTokenAccess("isAuthenticated()")
                .allowFormAuthenticationForClients();
    }

    /**
     * 用来配置客户端详情服务
     * @param clients
     * @throws Exception
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        /**client信息,可以存储数据库,可以redis,也可以存储内存,看你心情*/
        clients.inMemory()
                .withClient("system")
                .secret(passwordEncoder.encode("123456"))
                .authorizedGrantTypes("authorization_code", "refresh_token", "password")
                .scopes("app");
    }

    /**
     * 配置token
     * @param endpoints
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        /**直接存储内存*/
        endpoints
                .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST)
                .authenticationManager(authenticationManager)
                .tokenStore(new InMemoryTokenStore())
                .userDetailsService(userDetailsService);

    }
}

ResourceServerConfig资源服务器 这个类的作用是为Oauth请求服务,必须配置

/**
 * @Title: ResourceServerConfig
 * @description: 资源服务配置
 * @author: LIUFANG
 * @create: 2020/3/13 13:54
 * @Version: v1.0
 */
@Configuration
@EnableResourceServer
@Order(6)
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/admin/**").hasRole("ADMIN")
                .antMatchers("/user/**").hasAnyRole("ADMIN","USER")
                .antMatchers("/test").authenticated()
                .anyRequest().authenticated();
    }
}

controller调用

/**
 * @Title: MyController
 * @description: 测试Controller
 * @author: LIUFANG
 * @create: 2020/3/13 10:56
 * @Version: v1.0
 */
@RestController
public class MyController {
    @GetMapping(value = "/test")
    public Object test(){
        return "test";
    }

    @GetMapping(value = "/user")
    @PreAuthorize("hasAnyRole('ROLE_USER')")
    public Object user(){
        return "user";
    }

    @GetMapping(value = "/user/a")
    public Object user2(){
        return "user";
    }

    @PreAuthorize("hasAnyRole('ROLE_ADMIN')")
    @GetMapping(value = "/admin")
    public Object admin(){
        return "admin";
    }

    @GetMapping(value = "/admin/b")
    public Object admin2(){
        return "admin";
    }
}

http请求验证

/**http 请求 URL*/
GET http://localhost:8888/user/a
/**header中需要添加消息头:*/
Authorization: Bearer 775d36ad-d224-463b-8632-9cc4e9518d41

image.png

获取code

http://localhost:8080/oauth/authorize?client_id=system&response_type=code&scope=app&redirect_uri=http://www.baidu.com

使用code 获取access_token

curl -X POST -d "grant_type=authorization_code&code=Ii2ZNI&client_id=system&client_secret=123456&redirect_uri=http://www.baidu.com" http://localhost:8080/oauth/token 出参:

{
 "access_token": "df23f20a-59ee-4288-9582-040718846ff3",
 "token_type": "bearer",
 "refresh_token": "63b0ad83-6168-4b62-abeb-ab64d1154abd",
 "expires_in": 43199,
 "scope": "app"
}

参考: https://blog.csdn.net/liu__hui2008ooo/article/details/104904137

https://blog.csdn.net/qq_27828675/article/details/82466599

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×