SpringSecurity 笔记

整体概要

在这里插入图片描述

shiro相比,spring security 功能更全面,同样重量级也越大。shiro相对比较轻量。

spring security 本质就是过滤器链

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

松哥手把手带你捋一遍 Spring Security 登录流程

两个重要接口

UserDetailService

当什么都没有都没配置时,账号和密码都是由spring security自动生成的。实际中是由我们到数据库中进行查询的,自定义逻辑控制认证逻辑。

UsernamePasswordAuthenticaionFilter拦截请求路径为/login的post请求,随后验证用户名与密码。我们需要写一个类继承此类并重写他的三个方法

  1. attemptAuthentication 验证用户名与密码
  2. successfulAuthentication 验证成功
  3. unsuccessfulAuthentication 验证失败

UserDetailService接口 : 查询数据库用户名与密码的过程,返回User对象(此对象时spring security提供的对象)

PasswordEncoder

数据加密接口,用于返回user对象里面的密码加密

用户认证

设置用户名与密码

  1. 在配置文件中写
  2. 继承WebSecurityConfigurerAdapter,重写configure方法
  3. configure方法中利用UserDetailService的实现类查询数据库

而服务器识别Session的关键就是依靠一个名为JSESSIONID的Cookie。在Servlet中第一次调用req.getSession()时,Servlet容器自动创建一个Session ID,然后通过一个名为JSESSIONID的Cookie发送给浏览器:

这里要注意的几点是:

  • JSESSIONID是由Servlet容器自动创建的,目的是维护一个浏览器会话,它和我们的登录逻辑没有关系;
  • 登录和登出的业务逻辑是我们自己根据HttpSession是否存在一个"user"的Key判断的,登出后,Session ID并不会改变;
  • 即使没有登录功能,仍然可以使用HttpSession追踪用户,例如,放入一些用户配置信息等。

user类

public class User implements UserDetails, CredentialsContainer {
    private static final long serialVersionUID = 520L;
    private static final Log logger = LogFactory.getLog(User.class);
    private String password;
    private final String username;
    private final Set<GrantedAuthority> authorities;
    private final boolean accountNonExpired;
    private final boolean accountNonLocked;
    private final boolean credentialsNonExpired;
    private final boolean enabled;

spring security对User类进行验证时,首先先检查accountNonExpired;accountNonLocked等字段,有问题直接throw exception,没问题再查验密码。

初级自定义认证

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService myUserDetailService;

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

    /**
     * 自定义用户认真需要有Bean实现PassWordEncoder接口
     * @return
     */
    @Bean
    protected PasswordEncoder getPasswordEncoder(){
        return new BCryptPasswordEncoder();
    }
}
@Service
public class MyUserDetailService implements UserDetailsService {
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private UserMapper userMapper;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        //查询数据库,使用myabtis-plus
        QueryWrapper<Users> wrapper=new QueryWrapper<>();
        wrapper.eq("username",s);
        Users users = userMapper.selectOne(wrapper);
        if(users==null) throw new UsernameNotFoundException("用户名不存在");

        List<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList("admin");

        return new User(users.getUsername(),passwordEncoder.encode(users.getPassword()),authorities);
    }
}

WebSecurityConfigurerAdapter

configure(HttpSecurity http)方法

在这里插入图片描述

提交给loginProcessingUrl时,用户名与密码的key默认设置为usernamepassword,方法为post

Authentication

我们可以在任何地方注入 Authentication 进而获取到当前登录用户信息,Authentication 本身是一个接口,它有很多实现类。

在这众多的实现类中,我们最常用的就是 UsernamePasswordAuthenticationToken。

username 对应了 UsernamePasswordAuthenticationToken 中的 principal 属性,而 password 则对应了它的 credentials 属性。

User login_user= (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();

角色权限

hasAuthority:该角色是否拥有此权限。当权限不符合时,返回403。下图为写死权限,无法动态

在这里插入图片描述

hasAuthority 只有角色拥有其中之一的权限即可

在这里插入图片描述

RBAC动态权限设计

在这里插入图片描述

在这里插入图片描述

用户 —— 角色 : 一对多 ,角色 —— 权限 :一对多

WebSecurityConfigurerAdapter.configure()中,将权限从db提取出来并添加进SpringSecurityConfig中。

通常从Redis中拉去权限,可以将db中表定时写入Redis中

用户登录时,利用关联查询从db得到用户权限,写入User类中(User类需要继承SpringSecutiy的User类)。

在这里插入图片描述

oauth2

开放接口平台设计

http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html

微信授权

1、引导用户打开以下网页

https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx520c15f417810387&redirect_uri=https%3A%2F%2Fchong.qq.com%2Fphp%2Findex.php%3Fd%3D%26c%3DwxAdapter%26m%3DmobileDeal%26showwxpaytitle%3D1%26vb2ctag%3D4_2030_5_1194_60&response_type=code&scope=snsapi_base&state=123#wechat_redirect在这里插入图片描述

如果用户同意授权,页面将跳转至 redirect_uri/?code=CODE&state=STATE。

回调地址需要与在微信公众号平台登记的一致,否则显示回调地址错误。

2、获取code后,请求以下链接获取access_token: https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code在这里插入图片描述

正确时返回的JSON数据包如下:

{ 
"access_token":"ACCESS_TOKEN",
"expires_in":7200,
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID",
"scope":"SCOPE" 
}

在这里插入图片描述

Spring Secutiy Oauth2

Oauth 配置

@Component
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security
                //允许表单提交
                .allowFormAuthenticationForClients()
                //开启/oauth/token_key验证端口无权限访问
                .checkTokenAccess("permitAll()");
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        //这里写死在程序,实际中从db中捞数据
        clients.inMemory()
                //client id
                .withClient("PS5")
                //密码
                .secret(passwordEncoder.encode("123456"))
                //授权方式
                .authorizedGrantTypes("authorization_code")
                //权限范围
                .scopes("all")
                //资源id
                .resourceIds("PS5_resource")
                //回调地址
                .redirectUris("http://localhost:8081");
    }
    
}

启动后,访问以下链接,用户授权登录

http://localhost:8080/oauth/authorize?client_id=PS5&response_type=code

Spring JWT

大部分情况,token其实也存储redis中,并不是完全的无状态的。但是token本身含有用户的一些信息(payload),是通过Base64加密,透明的,所以比较只有一个SessionID更好。

目前企业可以单独出一个服务,专门记录、查询已登录的用户信息。在Redis中无法查询到此登录用户后,再去此服务中查询登录信息。

https://www.jianshu.com/p/6307c89fe3fa

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值