Spring Security里的authentication中加入自定义的内容

转载自:https://www.nbucedog.com/blog/article/8

叙述

当Spring security认证成功了之后会返回一个authentication,里面包含一些用户的认证信息。但有时候里面已有的信息并不能满足我们的需求,比如说当我们使用org.springframework.security.core.userdetails.User这个类的时候

代码

@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException{
    User user = userDAO.findByUsername(s);
    if(user==null){
        throw new UsernameNotFoundException("用户不存在");
    }
    Collection<GrantedAuthority> authorities = new ArrayList<>();
    for (Role role:user.getRoleSet()){
        for (Permission permission:role.getPermissionSet())
        authorities.add(new SimpleGrantedAuthority(permission.getPermission()));
    }
    return new org.springframework.security.core.userdetails.User(user.getUsername(),user.getPassword(),authorities);
}

会得到下面这样的authentication

{
    "authorities": [
        {
            "authority": "add_admin"
        }
    ],
    "details": {
        "remoteAddress": "0:0:0:0:0:0:0:1",
        "sessionId": null
    },
    "authenticated": true,
    "principal": {
        "password": null,
        "username": "nbucedog",
        "authorities": [
            {
                "authority": "add_admin"
            }
        ],
        "accountNonExpired": true,
        "accountNonLocked": true,
        "credentialsNonExpired": true,
        "enabled": true
    },
    "credentials": null,
    "name": "nbucedog"
}

可以看到这里关于用户的信息只有一个username,但其实我还想要用户的id,因为使用Spring注解进行权限认证时id会比username更保险(这个我后面会说)。

接下来我们看看怎么能够在authentication.principal里加入id吧

第一步:写一个实现UserDetails接口的类

import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.GrantedAuthority;
import java.util.Collection;

public class SecurityUser extends User{
    private Integer id;
    public SecurityUser(String username, String password, Collection<GrantedAuthority> authorities) throws IllegalArgumentException{
        super(username,password,authorities);
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
}

因为org.springframework.security.core.userdetails.User本身就是UserDetails的实现类,而且它里面有许多东西我们还要用,所以我们就直接继承它并加入自己的东西,这里加入一个id属性

第二步:在loadUserByUsername方法里使用这个自定义的类

@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException{
    System.out.println("UserService:"+s);
    User user = userDAO.findByUsername(s);
    if(user==null){
        throw new UsernameNotFoundException("用户不存在");
    }
    Collection<GrantedAuthority> authorities = new ArrayList<>();
    for (Role role:user.getRoleSet()){
        for (Permission permission:role.getPermissionSet())
        authorities.add(new SimpleGrantedAuthority(permission.getPermission()));
    }
    SecurityUser securityUser = new SecurityUser(user.getUsername(),user.getPassword(),authorities);
    securityUser.setId(user.getId());
    return securityUser;
}

这样之后,我们会得到一个authentication.principal里包含id的authentication

{
    "authorities": [
        {
            "authority": "add_admin"
        }
    ],
    "details": {
        "remoteAddress": "0:0:0:0:0:0:0:1",
        "sessionId": null
    },
    "authenticated": true,
    "principal": {
        "password": null,
        "username": "nbucedog",
        "authorities": [
            {
                "authority": "add_admin"
            }
        ],
        "accountNonExpired": true,
        "accountNonLocked": true,
        "credentialsNonExpired": true,
        "enabled": true,
        "id": 1
    },
    "credentials": null,
    "name": "nbucedog"
}

接下来我们就可以使用Spring注解进行权限配置了,比如要求只有用户自己能修改自己的用户信息

@RequestMapping(value = "/user",method = RequestMethod.PUT)
@ResponseBody
@PreAuthorize("#user.id==authentication.principal.id")
public Map UpdateUser(@RequestBody User user){
    try {
        User oldUser = userService.findById(user.getId());
        oldUser.setNickname(user.getNickname());
        oldUser.setSex(user.getSex());
        oldUser.setPhone(user.getPhone());
        oldUser.setMail(user.getMail());
        oldUser.setResume(user.getResume());
        userService.save(oldUser);
        return ResultTools.result(0);
    }catch (Exception e){
        e.printStackTrace();
        return ResultTools.dataResult(1000,e.getMessage());
    }
}

接下来说说在代码里我们为什么使用了authentication.principal.id,而非authentication.principal.username
这里举个例子,假如我们使用了@PreAuthorize("#user.username==authentication.principal.username"),而某个用户名为badguys,id为2的bad guys提交了如下的json数据

{
    "id":1,
    "username":"badguys",
    "nickname":"bad guys"
    ...
}

当id为2的bad guys用他自己注册的账户登录后,通过这个数据成功的通过了@PreAuthorize里的过滤条件,并且成功修改了id为1的用户信息。而当我们使用@PreAuthorize("#user.id==authentication.principal.id")时,这条带有攻击性的json数据则会被拦截。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Security,我们可以通过实现`AuthenticationProvider`接口来自定义身份验证提供程序,并在`AuthenticationManager`注册它。下面是一个简单的示例: 1. 创建一个自定义的身份验证提供程序 ```java @Component public class MyAuthenticationProvider implements AuthenticationProvider { @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { String username = authentication.getName(); String password = authentication.getCredentials().toString(); // 进行自定义的身份验证逻辑 if ("admin".equals(username) && "123456".equals(password)) { return new UsernamePasswordAuthenticationToken(username, password, new ArrayList<>()); } else { throw new BadCredentialsException("Authentication failed"); } } @Override public boolean supports(Class<?> authenticationType) { return authenticationType.equals(UsernamePasswordAuthenticationToken.class); } } ``` 2. 注入自定义的身份验证提供程序到`AuthenticationManager` ```java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private MyAuthenticationProvider myAuthenticationProvider; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(myAuthenticationProvider); } // ... 省略其他配置 ... } ``` 在以上示例,我们通过实现`AuthenticationProvider`接口,自定义了一个名为`MyAuthenticationProvider`的身份验证提供程序。在`configure(AuthenticationManagerBuilder auth)`方法,我们通过调用`auth.authenticationProvider(myAuthenticationProvider)`方法将该提供程序注册到`AuthenticationManager`。这样,当用户在登录时,`AuthenticationManager`就会自动调用`MyAuthenticationProvider`的`authenticate`方法进行身份验证。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值