spring boot Security Oauth2.0最简版本集成

spring boot Security Oauth2.0最简版本集成

搭建最简版本,工具IntelliJ idea,构建方式maven,话不多说,上代码
请同学们理性看待最简开发模式,真实开发涉及的内容非常多,只做思路

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

spring security的配置

/**
 * @Title: SecurityConfig
 * @description: 权限配置
 * @author: LIUFANG
 * @create: 2020/3/13 9:12
 * @Version: v1.0
 */
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
@Configuration
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.authorizeRequests()
                .antMatchers("/admin/**").hasRole("ADMIN")
                .antMatchers("/user/**").hasAnyRole("ADMIN","USER")
                .antMatchers("/test").authenticated()
                .anyRequest().authenticated().and()
                /**因为已经加入了其他的认证,此处这个basic咱们就不用了*/
                //.httpBasic().and()
                .csrf()
                .disable();
    }

    @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
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";
    }
}

验证

Token的获取

postman直接粘贴下面请求进去即可

http://127.0.0.1:8888/oauth/token?username=user&password=123456&client_id=system&client_secret=123456&grant_type=password

正确结果为:
在这里插入图片描述

http请求验证

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

在这里插入图片描述

可能出现的问题

在搭建的时候碰见比较多的问题:

  • 密码的加密规则的选择,你会看到有人选择让你用明文传输(而且是官方已经不推荐的方式,那使用它的目的是什么,只是单纯的跑通,建议多思考)
  • AuthenticationManager,security的认证,你要也要告诉Oauth,记得重写WebSecurityConfigurerAdapter类
  • 授权,很多小伙伴都是急匆匆的把security+oauth搭建起来,发现各种问题,比如401,或者服务认证失败,如果你想看源码, 一定先看security的源码,因为你的问题8成就在这里,不要上来就直接断点到org.springframework.security.oauth2.provider.endpoint.TokenEndpoint类,你会发现根本解决不了问题(最后在啰嗦一遍,先搭建你的boot+security,在加入oauth)
  • 最后就是请求的客户端,因为我们使用的内存存储方式,你在看secret的时候,让他你在此处加入的内容时什么,如果你在此处加入其它的元素,你会发现无法通过,我没有去深究源码,感兴趣的朋友自己可以去看一下
    在这里插入图片描述

总结

小伙伴建议搭建的思路是先搭建 spring boot + spring security,保证你的鉴权是OK,spring boot 1.x版本和2.x版本是有区别的,搭建的时候自行查看文档,那么Oauth的集成速度就很快了,最后说一下。
不建议出问题首先从源码找原因,官网文档和小伙伴的博客可以作为首选,在配合跟踪源码,更容易理解,前人栽的树,你不用多浪费资源

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值