【问题标题】:Spring boot how make a user role managing with jwtSpring Boot 如何使用 jwt 管理用户角色
【发布时间】:2017-09-01 09:31:54
【问题描述】:

我正在用 spring boot 编写一个 RESTful api。 我正在使用 spring boot、jersey、mongo db、swagger、spring boot security 和 jwt。

我已经编写了模型和数据库请求的存储库。现在我已经集成了 Security 和 jwt 令牌。

现在我需要离散化用户的角色,因为用户无法调用需要管理员权限的路由。

我有一个登录路径,它返回一个令牌。这是我的 SecurityConfig 的代码

...
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{

    @Autowired
    UserRepository userRepository;

    @Override
    public void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.csrf().disable().authorizeRequests()
                .antMatchers("/").permitAll()
                .antMatchers("/api/swagger.json").permitAll()
                .antMatchers(HttpMethod.POST, "/login").permitAll()
                .antMatchers("/api/*").authenticated()
                .and()

                .addFilterBefore(new JWTLoginFilter("/login", authenticationManager(), userRepository),
                        UsernamePasswordAuthenticationFilter.class)

                .addFilterBefore(new JWTAuthenticationFilter(),
                        UsernamePasswordAuthenticationFilter.class);
    }

}

我编写了 JWTLoginFilter,当用户登录时返回我的令牌

...
@Override
public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res) throws AuthenticationException, IOException, ServletException {
    Credential creds = new ObjectMapper().readValue(req.getInputStream(), Credential.class);

    User user = userRepository.login(creds);

    if (user == null)
        throw new BadCredentialsException("");

    UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
        creds.getUsername(),
        creds.getPassword()
    );

    return token;
}
...

我想在方法的端点类上插入这个

@PreAuthorize("hasRole('ROLE_ADMIN')")

这是端点的一部分

....

@Component
@Path("story")
@Api(value = "Story", produces = "application/json")
public class StoryEndpoint {

    private static final Logger LOGGER = LoggerFactory.getLogger(StoryEndpoint.class);

    @Autowired
    StoryRepository storyRepository;


    @GET
    @Path("/")
    @Produces(MediaType.APPLICATION_JSON)
    @PreAuthorize("hasRole('ROLE_ADMIN')") <--- I want insert here
    @ApiOperation(value = "Get All Story", response = Story.class)
    @ApiResponses(value = {
            @ApiResponse(code = 200, message = "hello resource found"),
            @ApiResponse(code = 404, message = "Given admin user not found")
    })
    public Response getAllStory(){
        Iterable<Story> stories = storyRepository.findAll();
        LOGGER.info("getAllStory");
        return (stories!=null) ? Response.ok(stories).build() : Response.ok(ResponseErrorGenerator.generate(Response.Status.NOT_FOUND)).status(Response.Status.NOT_FOUND).build();
    }
....

如何制定一种机制来为用户分配角色以及如何在令牌中传递角色并离散化路由用户角色?

【问题讨论】:

  • 不要混合权限和角色(带有“ROLE_”前缀的权限),使用hasRole('ADMIN')hasAuthority('ROLE_ADMIN')

标签: java spring-boot spring-security jwt roles


【解决方案1】:

您需要将用户角色存储在 JWT 令牌中作为附加声明,在令牌验证后提取它们并作为主体的“权限”传递:

 Collection<? extends GrantedAuthority> authorities
                = Arrays.asList(claims.get(AUTHORITIES_KEY).toString().split(",")).stream()
                .map(authority -> new SimpleGrantedAuthority(authority))
                .collect(Collectors.toList());

        User principal = new User(claims.getSubject(), "",
                authorities);

        UsernamePasswordAuthenticationToken t
                = new UsernamePasswordAuthenticationToken(principal, "", authorities);

【讨论】:

  • 我需要修改我的用户类吗?我还没有理解代码的第一部分。我在哪里插入这段代码? @Alex Chemyshev
  • 代码的第一部分是关于角色名称的提取列表,用','分隔。你应该把这个代码而不是' UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken( creds.getUsername(), creds.getPassword() );'
  • 但您还需要将角色列表添加到 JWT 令牌中,否则它将不起作用。也许 Spring 和 JWT auth 的完整解决方案会更好地帮助您:github.com/jhipster/jhipster-sample-app-token/blob/master/src/…
  • 我尝试更改代码,但它不起作用并且我没有收到错误。我无法理解我错在哪里。 gist.github.com/paranoiasystem/83cc4cae0235a54b2c778145f28b2aa5
  • gist.github.com/paranoiasystem/… 你需要在这里输入登录名而不是整个对象
【解决方案2】:

您应该将角色添加到令牌中,例如您可以参考以下链接:- http://www.svlada.com/jwt-token-authentication-with-spring-boot/

【讨论】:

    【解决方案3】:

    首先需要在 JWT 中添加角色。为此,您可以在 JWT 生成器类中添加为声明。

        public String generateToken(UserDetails userDetails) {
            Map<String, Object> claims = new HashMap<>();
            Set<String> Userroles = new HashSet<>();
            User user = userRepository.findByUsername(userDetails.getUsername());
            for(Role role:user.getRoles()){
                Userroles.add(role.getName());
            }
            claims.put("Roles",Userroles.toArray());
            return createToken(claims, userDetails.getUsername());
        }
    
        private String createToken(Map<String, Object> claims, String subject) {
            
            return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis()))
                    .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10))
                    .signWith(SignatureAlgorithm.HS256, SECRET_KEY).compact();
        }
    

    在用户模型类中需要包含Set或任何其他数据结构中的角色。

     @ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
        @JoinTable(name = "USER_ROLES", joinColumns = {
                @JoinColumn(name = "USER_ID") }, inverseJoinColumns = {
                @JoinColumn(name = "ROLE_ID") })
        private Set<Role> roles;
    

    在 Repository 中需要有如下方法。

    User findByUsername(String username);
    

    请查看此 Github Repo(https://github.com/Senthuran100/SpringBoot_JWT) 以供参考。

    【讨论】:

      猜你喜欢
      • 2012-08-16
      • 2020-07-25
      • 2016-10-03
      • 2018-04-27
      • 2017-04-04
      • 1970-01-01
      • 2011-03-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多